我在C中有一个像这样的联盟:
union AUnion {
struct CharBuf {
char *buf;
size_t len;
} charbuf;
uint8_t num;
double fp_num;
};
我的问题是,如果给出以下内容,我可以保证:
union AUnion u;
以下是真的:
&u == &u.num
&u == &u.fp_num
&u == &u.charbuf
即,它们都始于存储u
的内存段的开头。
对于使用gcc version 5.3.0
和-std=c11
编译的此C程序,上述情况属实:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
union AUnion {
struct CharBuf {
char *buf;
size_t len;
} charbuf;
uint8_t num;
double fp_num;
};
int main(void)
{
union AUnion u;
printf("%d\n", ((void*)&u) == ((void*)&u.charbuf));
printf("%d\n", ((void*)&u.charbuf) == ((void*)&u.num));
printf("%d\n", ((void*)&u.num) == ((void*)&u.fp_num));
}
打印时:
1
1
1
使用相同的编译器将上面的代码编译为C ++ 11会产生与将其编译为C11相同的输出。
但这是标准化行为吗?这是不确定的?我可以依赖大多数C编译器的这种行为吗?我也可以期待C ++编译器的这种行为吗?
答案 0 :(得分:13)
在6.7.2.1p16中,C标准保证:
联合的大小足以包含其最大的成员。最多一个成员的值可以随时存储在union对象中。 指向联合对象的指针(适当转换)指向其每个成员(或者如果成员是位字段,则指向它所在的单位),反之亦然。
所以,是的,你可以依赖从union
地址开始的所有成员(注意struct
的第一个成员也是如此)。
C ++标准包含一个与C风格相似的句子(即只有C风格的成员)union
s / struct
,因为C ++允许将union
传递给C函数确实需要这种布局.C ++标准中的相关部分是9.5。
但是,请注意标准简单类型(整数,浮点数)中可能存在填充位。他们的内部可能会有所不同(结束)。您还可能违反严格别名规则(C:有效类型)。
答案 1 :(得分:10)
根据我的经验,我会说“是的”,虽然我已经检查了C++14 standard,但它甚至保证了这一点。 (c ++ 11很可能会产生相同的效果)第9.5章规定:All non-static data members of a union object have the same address
所以,你可以依赖这种行为。