Как скомпилировать C-код с анонимными структурами / объединениями?

Я могу сделать это в c ++ / g ++:

struct vec3 { union { struct { float x, y, z; }; float xyz[3]; }; }; 

Затем,

 vec3 v; assert(&v.xyz[0] == &v.x); assert(&v.xyz[1] == &v.y); assert(&v.xyz[2] == &v.z); 

будет работать.

Как это сделать в c с gcc? у меня есть

 typedef struct { union { struct { float x, y, z; }; float xyz[3]; }; } Vector3; 

Но я получаю ошибки вокруг, в частности

 line 5: warning: declaration does not declare anything line 7: warning: declaration does not declare anything 

в соответствии с http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields

-fms-extensions позволят вам использовать функцию (и я).

(Этот ответ относится к C99, а не C11).

C99 не имеет анонимных структур или союзов. Вы должны назвать их:

 typedef struct { union { struct { float x, y, z; } individual; float xyz[3]; } data; } Vector3; 

И тогда вы должны использовать это имя при обращении к ним:

 assert(&v.data.xyz[0] == &v.data.individual.x); 

В этом случае, поскольку ваша структура верхнего уровня имеет единственный элемент объединения типов, вы можете упростить это:

 typedef union { struct { float x, y, z; } individual; float xyz[3]; } Vector3; 

и доступ к данным теперь становится следующим:

 assert(&v.xyz[0] == &v.individual.x); 

Новый стандарт C11 будет поддерживать анонимные структуры и союзы, см. Предисловие к абз. 6 апрельского проекта 2011 года.

http://en.wikipedia.org/wiki/C1X

Странная часть состоит в том, что gcc и clang теперь поддерживают анонимные структуры и объединения в режимах C89 и C99. На моей машине не появляется никаких предупреждений.

Можно также всегда делать следующее:

 typedef struct { float xyz[0]; float x, y, z; }Vec3; 

Массив нулевой длины не выделяет никакого хранилища и просто указывает C «указывать на то, что было объявлено следующим объявлением». Затем вы можете получить к нему доступ, как и любой другой массив:

 int main(int argc, char** argv) { Vec3 tVec; for(int i = 0; i < 3; ++i) { tVec.xyz[i] = (float)i; } printf("vec.x == %f\n", tVec.x); printf("vec.y == %f\n", tVec.y); printf("vec.z == %f\n", tVec.z); return 0; } 

Результат:

 vec.x == 0.000000 vec.y == 1.000000 vec.z == 2.000000 

Если вы хотите быть лишним параноиком, вы можете вручную указать страtagsю упаковки данных в соответствии с вашей платформой.

Анонимные союзы – это особенность языка C ++. Язык C не имеет анонимных союзов.

Анонимные структуры не существуют ни в C, ни в C ++.

Объявление, которое вы представили в своем вопросе, может компилироваться с помощью GCC C ++, но это будет просто расширение для компилятора, которое не имеет ничего общего ни с стандартным C, ни с стандартным C ++.

Кроме того, независимо от того, как вы его реализуете, ни языки C, ни C ++ не гарантируют, что ваши утверждения будут сохранены.

Я могу сделать это в GCC без предупреждения

 typedef union { struct { // human-friendly access float x; float y; float z; float w; }; float xyz[3]; struct { // human-friendly access float r; float g; float b; float a; }; float rgb[3]; } Vector4f; int main() { Vector4f position, normal, color; // human-friendly access position.x = 12.3f; position.y = 2.f; position.z = 3.f; position.w = 1.f; normal.x = .8f; normal.y = .9f; normal.z = .1f; normal.w = 1.f; color.r = 1.f; color.g = .233f; color.b = 2.11f; color.a = 1.1f; // computer friendly access //some_processor_specific_operation(position.vec,normal.vec); return 0; } 

C: \> gcc vec.c -Wall

C: \> gcc –version gcc (GCC) 4.4.0 Copyright (C) 2009 Free Software Foundation, Inc. Это бесплатное программное обеспечение; см. источник условий копирования. НЕТ никакой гарантии; даже для КОММЕРЧЕСКОЙ ЦЕННОСТИ или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ.

Объединения анонимы также не поддерживаются C.

Также обратите внимание, что если вы объявите это так:

 typedef struct { union { struct { float x, y, z; } individual; float xyz[3]; } data; } Vector3; 

дела

 Vector3 v; v.data.xyz[0] = 5; float foo = v.data.individual.x; 

Неопределенное поведение. Вы можете получить доступ только к последнему назначенному члену объединения. В вашем случае использование объединения является неправильной и плохой практикой кодирования, поскольку оно зависит от многих вещей, которые не указаны в стандарте (padding …).

В C вы предпочтете что-то вроде этого:

 typedef struct { float v[3]; } Vec3; 

И если вы не хотите использовать v [x], вы можете подумать:

 #define X(V) ((V).v[0]) Vec3 v; X(v) = 5.3; printf("%f\n", X(v)); 

Диалог GNU на C поддерживает анонимные структуры / объединения, но по умолчанию GCC компилируется с использованием какого-то стандарта C. Чтобы использовать диалект GNU, поместите «-std = gnu99» в командной строке.

Неопознанные члены структуры, не являющиеся стандартом ANSI / ISO C99, объясняют это, но я нахожу забавную вещь, на некоторых портах версий GNU C Compiler 2.xx, используя неиспользуемые элементы структуры, она находит их, не говорит такие вещи, как ” x не является членом union \ struct y, что такое x? “, в других случаях это ol ‘” x undefined “,” x не является членом структуры “, черт возьми, я клянусь, что увидел” указатель на неизвестный «через некоторое время назад, из-за этого.

Поэтому я профессионально поеду со всеми остальными на этом, и просто эфир предоставит члену struct \ union идентификатору, или, в случае UNION, тщательно перестройте код, чтобы союз оказался идентифицированным членом идентифицированной структуры и членов, которые были встроены в неопознанную структуру исходного союза, стали членами идентифицированной структуры и тщательно используются с идентифицированным членом профсоюза. Но в тех случаях последний метод не был бы выполнимым заменителем, я просто дал бы досадную структуру идентификатору и двигался дальше.

Я могу предложить интересное обходное решение, чтобы избежать слишком большого количества полей внутри структуры. Один из них предупреждает об именах, называемых именами, так как он может создавать конфликты.

 #define x ___fl_fld[0] #define y ___fl_fld[1] #define z ___fl_fld[2] #define w ___fl_fld[3] #define r ___fl_fld[0] #define g ___fl_fld[1] #define b ___fl_fld[2] #define a ___fl_fld[3] typedef union { float ___fl_fld[4]; float xyz[3]; float rgb[3]; } Vector3; 

Вы можете получить доступ к структуре следующим образом:

 Vector3 v; assert(&v.x == &v.r); //Should return true 

Чтобы закончить, это будет объединение нескольких типов, совместимое с C99:

 #define u8llsb __u8[0] #define u8lmsb __u8[1] #define u8mlsb __u8[2] #define u8mmsb __u8[3] #define u16lsb __u16[0] #define u16msb __u16[1] #define u16 __u16[0] #define u8lsb __u8[0] #define u8msb __u8[1] typedef union { uint32_t u32; int32_t i32; uint16_t __u16[2]; uint8_t __u8[4]; } multitype_t; multitype_t Var; var.u32; var.i32; var.u8llsb; /* etc. */ 
Давайте будем гением компьютера.