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 风格成员)unions/structs,因为 C++ 允许通过 union s 到 C 函数确实需要此 layout.The C++ 标准中的相关部分是 9.5.


但是,请注意标准简单类型(整数、浮点数)中可能有填充。他们的内部可能会有所不同(字节顺序)。您也可能违反了严格的别名规则(C:有效类型)。