C/C++联合中元素的内存位置
Memory position of elements in C/C++ union
我在 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++ 编译器的这种行为吗?
根据我的经验,我会说 'yes',尽管我已经检查了 C++14 standard,它甚至可以保证这一点。 (c++11 很可能会产生相同的效果)第 9.5 章指出:All non-static data members of a union object have the same address
所以,你可以依赖这个行为。
在 6.7.2.1p16 中,C 标准保证:
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.
所以,是的,您可以依赖从 union
地址开始的所有成员(请注意,这与 struct
的第一个成员相同)。
C++ 标准包括关于 C 风格的类似句子(即仅 C 风格成员)union
s/struct
s,因为 C++ 允许通过 union
s 到 C 函数确实需要此 layout.The C++ 标准中的相关部分是 9.5.
但是,请注意标准简单类型(整数、浮点数)中可能有填充位。他们的内部可能会有所不同(字节顺序)。您也可能违反了严格的别名规则(C:有效类型)。
我在 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++ 编译器的这种行为吗?
根据我的经验,我会说 'yes',尽管我已经检查了 C++14 standard,它甚至可以保证这一点。 (c++11 很可能会产生相同的效果)第 9.5 章指出:All non-static data members of a union object have the same address
所以,你可以依赖这个行为。
在 6.7.2.1p16 中,C 标准保证:
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.
所以,是的,您可以依赖从 union
地址开始的所有成员(请注意,这与 struct
的第一个成员相同)。
C++ 标准包括关于 C 风格的类似句子(即仅 C 风格成员)union
s/struct
s,因为 C++ 允许通过 union
s 到 C 函数确实需要此 layout.The C++ 标准中的相关部分是 9.5.
但是,请注意标准简单类型(整数、浮点数)中可能有填充位。他们的内部可能会有所不同(字节顺序)。您也可能违反了严格的别名规则(C:有效类型)。