C/C++联合中元素的内存位置

A_U*_*ser 15 c c++ unions c++11 c11

我在C中有一个这样的联盟:

union AUnion {
  struct CharBuf {
    char *buf;
    size_t len;
  } charbuf;
  uint8_t num;
  double fp_num;
};
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果给出以下内容,我可以保证:

union AUnion u;
Run Code Online (Sandbox Code Playgroud)

那么以下是真的:

&u == &u.num
&u == &u.fp_num
&u == &u.charbuf
Run Code Online (Sandbox Code Playgroud)

即它们都从u存储的内存段的开头开始.

在编译这个C程序的情况下,gcc version 5.3.0-std=c11上述是真实的:

#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));
}
Run Code Online (Sandbox Code Playgroud)

打印时:

1
1
1
Run Code Online (Sandbox Code Playgroud)

使用相同的编译器将上面的代码编译为C++ 11会产生与将其编译为C11相同的输出.

但这是标准化的行为吗?这是不确定的?我可以依赖大多数C编译器的这种行为吗?我可以期待C++编译器的这种行为吗?

too*_*ite 13

6.7.2.1p16中,C标准保证:

联合的大小足以包含其最大的成员.最多一个成员的值可以随时存储在union对象中.指向适当转换的联合对象的指针指向其每个成员(或者如果成员是位字段,则指向它所在的单元),反之亦然.

所以,是的,你可以依赖从unions地址开始的所有成员(注意这对于a的第一个成员是相同的struct).

C++标准包含一个关于C风格(即只有C风格的成员)unions/structs 的类似句子,因为C++允许将unions 传递给需要这种布局的C函数.C++标准中的相关部分是9.5.


但是,请注意标准简单类型(整数,浮点数)中可能存在填充.他们的内部可能会有所不同(结束).您还可能违反严格的别名规则(C:有效类型).


JVA*_*pen 10

根据我的经验,我会说'是',虽然我已经检查了C++ 14标准,它甚至可以保证这一点.(c ++ 11很可能会产生相同的效果)第9.5章规定:All non-static data members of a union object have the same address

所以,你可以依赖这种行为.