我可以用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
答案 0 :(得分:51)
根据http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields
-fms-extensions
将启用您(和我)想要的功能。
答案 1 :(得分:32)
(这个答案适用于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);
答案 2 :(得分:25)
新的C11标准将支持匿名结构和工会,见前言2011年4月草案第6段。
http://en.wikipedia.org/wiki/C1X
奇怪的是,gcc和clang现在都支持C89和C99模式下的匿名结构和联合。在我的机器上没有出现警告。
答案 3 :(得分:11)
也可以始终执行以下操作:
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
如果您想要更加偏执,可以手动指定数据打包策略以适合您的平台。
答案 4 :(得分:8)
匿名联盟是C ++语言的一个特性。 C语言没有匿名联盟。
C和C ++都不存在匿名结构。
您在问题中提出的声明可能会使用GCC C ++编译器进行编译,但它只是一个特定于编译器的扩展,与标准C和标准C ++无关。
最重要的是,无论你如何实现它,C和C ++语言都不能保证你的断言能够成立。
答案 5 :(得分:3)
我可以在没有警告的情况下在海湾合作委员会这样做
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:\&gt; gcc vec.c -Wall
C:\&gt; gcc --version gcc(GCC)4.4.0 版权所有(C)2009 Free Software Foundation,Inc。 这是免费软件;查看复制条件的来源。没有 保证;甚至不适用于适销性或特定用途的适用性。
答案 6 :(得分:2)
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));
答案 7 :(得分:0)
C的GNU方言支持匿名结构/联合,但默认情况下GCC使用某种标准C编译。要使用GNU方言,请在命令行中输入“-std = gnu99”。
答案 8 :(得分:0)
未被识别的结构成员不是ANSI / ISO C99标准解释了这一点,但我发现一个有趣的事情发生在GNU C Compiler 2.xx版本的某些端口上,使用未识别的结构成员工作,它找到它们,不说像“x不是union \ struct y的成员,什么是x?”之类的东西,其他时候,它是ol'“x未定义”,“x不是struct的成员”,我发誓,我看到了“指向未知的“一次又一次,因为这个。
所以我,专业地会和其他人一起做这个并且只是以太给struct \ union成员一个标识符,或者在UNIONs的情况下,仔细重新排列代码,以便联合最终成为已识别结构的已识别成员,嵌入原始联盟的未识别结构中的成员,成为已识别结构的成员,并与已识别的工会成员一起使用。 但是在那些情况下,后一种方法不会是一种可行的替代方法,我只是给annoynous结构一个标识符并继续前进。
答案 9 :(得分:-1)
我可以建议一个有趣的解决方法,以避免结构中的太多字段。建议人们警告简单的命名定义,因为它可能会产生冲突。
#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. */