Как скомпилировать 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
10 ответов:
согласно 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);
в этом случае, поскольку ваша структура верхнего уровня имеет один элемент типа union, вы можете упростить это:
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
Если вы хотите быть дополнительным параноиком, вы можете вручную указать стратегию упаковки данных в соответствии с вашей платформой.
анонимные объединения-это особенность языка C++. Язык C не имеет анонимных союзов.
анонимные структуры не существуют ни в C, ни в C++.
объявление, которое вы представили в своем вопросе, может быть скомпилировано с помощью gcc c++ complier, но это будет просто расширение для компилятора, которое не имеет ничего общего ни со стандартным 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;
- это неопределенное поведение. Вы можете получить доступ только к последнему назначенному члену профсоюза. В вашем случае использование объединения является неправильной и плохой практикой кодирования, поскольку она зависит от многих вещей, которые не указаны в стандарте (заполнение...).
В 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 2 происходит забавная вещь.X. X версии, используя неидентифицированные элементы структуры работает, он находит их, не говорит такие вещи, как " x не является членом union\struct y, что такое x?", в других случаях, это ol '"x не определен", "x не является членом структуры", черт возьми, я клянусь, что видел "указатель на неизвестное" однажды, из-за этого.
Так что я, профессионально пошел бы с все остальные на этом и просто эфире дают struct\Union member идентификатор, или в случае союзов, тщательно перестраивают код, чтобы союз заканчивался идентифицированным членом идентифицированной структуры, а члены, которые были встроены в неопознанную структуру исходного союза, становятся членами идентифицированной структуры и тщательно используются с идентифицированным членом Союза. Но в тех случаях, когда последний метод не был бы работоспособной заменой, я бы просто дал раздражает структура идентификатора и двигаться дальше.
Я могу предложить интересный обходной путь, чтобы избежать слишком много полей в структуре. Рекомендуется предупреждать о просто названных определениях, так как это может создать конфликты.
#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. */