Доступ к первому полю структуры в объединении структур

У меня есть три структуры, которые разделяют первый тип и имя первого поля:

struct TYPEA {
  char *name;
  int x,y;   /*or whatever*/
};

struct TYPEB {
  char *name;
  float a[30]; /*or whatever*/
};

struct TYPEC {
  char *name;
  void *w,*z; /*or whatever*/
};

Если я правильно помню, первое поле структуры должно начинаться с того же адреса, что и сама структура.

Это заставляет меня задуматься, верно ли то же самое для союза:

union data {
  struct TYPEA;
  struct TYPEB;
  struct TYPEC;
};

union data *p = function_returning_a_sane_default_for_union_data();
printf("%s", (char*) p);

У меня есть 2 вопроса относительно этого:

  1. Стандарты требуют, чтобы союзы всегда имели свой контент по одному адресу?
  2. сработало бы, если бы все структуры имели одинаковые поля, отличающиеся только по названию?

1 ответ

Решение

Первый элемент struct или же union гарантированно имеет то же значение адреса, что и struct´/сам союз. Видимо, это не тот же тип!

Для вашего использования вам не нужно приведение и на самом деле следует избегать его:

6.5.2.3p6: Одна специальная гарантия сделана для упрощения использования объединений: если объединение содержит несколько структур, которые имеют общую начальную последовательность (см. Ниже), и если объект объединения в настоящее время содержит одну из этих структур, это разрешается проверять общую начальную часть любого из них везде, где видна декларация заполненного типа объединения....

Так что вы могли бы (см. Ниже) просто

printf("%s", p->name);

(Примечание: что вы используете неназванный union члены не являются стандартным компилятором. Это (очень полезное) расширение gcc (-fms-extensionsПо крайней мере, также поддерживается MSVC тоже).)

Но: код в вашем вопросе неверен. Вы должны назвать каждого члена объединения или иметь декларатор типа с каждым членом. С тем же первым участником, он не будет уничтожен, потому что имена членов таких неназванных членов должны быть уникальными (как иначе они должны быть доступны по отдельности?). Так что это не будет действительно работать. Что вы могли бы сделать, это:

union data {
    struct TYPEA typea;
    struct TYPEB typeb;
    struct TYPEC typec;
};

а также

printf("%s", p->typea.name);

даже если struct содержит значение TYPEB В настоящее время.


Альтернативным и более понятным способом было бы завернуть union в struct:

struct TypeA {
    int x,y;
};

...

struct data {
    char *name;
    union {
        struct TypeA;
        struct TypeB;
        struct TypeC;
    };
};

При этом также используется расширение gcc на двух уровнях: для внешнего struct и union, Таким образом, он требует уникальных имен для всех возможных путей. Если вы хотите быть на 100% совместимым, назовите каждого члена как выше и используйте полный путь доступа.

Примечание: я удалил name член изнутри structв union и переместил его на внешний struct, Я также изменил имена. Единственным хорошо принятым соглашением об именах в C является использование заглавных букв только для макросов.

Другие вопросы по тегам