Подтвердить что ты не робот

Является ли листинг указателя на различные структуры, которые могут быть значимыми в C89?

У меня есть две структуры, такие как

struct X {
  int x;
  double *y;
};

struct Y {
  int a;
  double *b;
  char c;
};

Является ли указатель на struct Y указателем на struct X гарантированно вести себя разумно (т.е. x->x и x->y соответствует y->a и y->b соответственно) стандартом C89? Менее важно, но было бы здорово, если бы вы также знали, что это справедливо и для более поздних стандартов (например, C11) и других языков, которые имеют существенное синтаксическое и семантическое совпадение с C (например, С++ XX, Objective-C )?

4b9b3361

Ответ 1

Это поведение undefined. Python полагался на это раньше и должен был исправить это. Если у вас есть struct Y include struct X в качестве своего первого элемента, вы можете использовать его для аналогичный эффект:

struct Y {
    struct X a;
    char c;
};

struct Y y;
struct X *x = (struct X *) &y; /* legal! */

Также существует специальный случай для объединений:

struct X {
  int x;
  double *y;
};

struct Y {
  int a;
  double *b;
  char c;
};

union XY {
    struct X x;
    struct Y y;
};

union XY xy;
xy.x.x = 0;
printf("%d\n", xy.y.a); /* legal! */

В более поздних версиях стандарта C компилятор должен только обрабатывать объекты X и Y, псевдонизирующие друг друга, если такое определение объединения действительно в области видимости, но на C89 оно в основном должно принимать такие определение существует где-то. Тем не менее, это не делает безопасным применение struct Y * к struct X *; если компилятор знает, что конкретный struct Y не является частью объединения, он все равно может предположить, что struct X * не может его псевдонизировать.

Ответ 2

C89 разрешает преобразование путем литья указателя на один тип объекта на указатель на другой тип объекта.

Однако до того, как мы даже разойдемся с разыменованием, конвертированный указатель гарантированно будет действительным вообще, только если ссылочный тип исходного указателя требует выравнивания, по меньшей мере, такого же строгого, как у типа, на который ссылается указатель результата. Выравнивание полностью зависит от реализации. В вашем конкретном примере, скорее всего, но не гарантируется, что два типа struct будут иметь одинаковое требование выравнивания.

Предполагая, что преобразование действительно приводит к действительному указателю, стандарт не определяет точно, как элементы struct располагаются внутри представления объекта struct. Члены должны отображаться в том же порядке, что и в определении struct, и не должно быть никаких отступов до первого, но никакие другие детали не определены. Поэтому в вашем примере гарантируется, что X->x будет соответствовать Y->a (предположим, опять же, что преобразованный указатель действителен в первую очередь), но undefined соответствует ли X->y Y->b.