如何用匿名结构/联合来编译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); 

将工作。

如何使用gcc在c中执行此操作? 我有

 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将启用你(和我)想要的function。

(这个答案适用于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); 

在这种情况下,因为您的顶级结构有一个单一的types联合项目,您可以简化:

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

现在访问数据变成:

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

新的C11标准将支持匿名结构和联盟,请参见2011年4月草案的前言第6段。

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 ++编译器进行编译,但它只是一个编译器特定的扩展,与标准C和标准C ++都没有关系。

最重要的是,无论你如何实现它,C语言和C ++语言都不能保证你的断言能保持。

匿名工会也不支持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)); 

我可以在没有警告的情况下在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版权所有(C)2009自由软件基金会,这是自由软件; 请参阅复制条件的来源。 没有保修; 甚至不适用于适销性或针对特定用途的适用性。

C的GNU方言支持匿名结构/联合,但默认情况下,GCC使用某种标准C编译。要使用GNU方言,请在命令行中input“-std = gnu99”。

身份不明的struct成员不是ANSI / ISO C99标准解释这一点,但我发现一个有趣的事情发生,在GNU C编译器2.xx版本的一些端口,使用未标识的结构成员的作品,它发现他们,并没有说像“ x不是union \ struct y的成员,什么是x?“,其他时候,它是ol”x是undefined“,”x不是struct的成员“,地狱我发誓我看到一个”指向未知“一会儿回来,由于这个。

所以我在专业上会和其他所有人一样,只要给结构\联盟成员一个标识符,或者在联盟的情况下,仔细地重新排列代码,这样联合结束了一个确定的结构的标识成员和成员被embedded原始联盟的不明身份结构中,成为已确定结构的成员,并与已确定的联盟成员一起使用。 但在这种情况下,后一种方法将不是一个可行的替代品,我只是给这个令人讨厌的结构一个标识符并继续前进。

我可以build议一个有趣的解决方法,以避免在结构中的太多领域。 build议一个提醒简单命名的定义,因为它可能会产生冲突。

 #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的多types联合:

 #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. */