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