联合声明的两种不同语法如何给我不同的大小?

How does the two different syntax of union declaration give me different size?

我在结构中声明一个联合数据类型(但有两种不同的语法)。对于结构的大小,我得到了不同的输出。这里有什么问题?

union u {
    double x;
    int y;
};

union {
    double x;
    int y;
} u_1;

struct s1 {
    int a;
    union {
        int b;
        double c;
    };
};  

struct s2 {
    int a;
    union u{
        int b;
        double c;
    };
};

int main()
{
    u u1;
    s1 s_1;
    s2 s_2;

    cout<< sizeof(u1)<< " "<<sizeof(u_1)<<" " <<sizeof(s_1)<<" " <<sizeof(s_2);
}

我期望输出:8 8 16 16 但实际输出是 8 8 16 4。

s2 声明了一个联合但没有成为它的成员。
s1 正在使用 "anonymous union" 语义:(来自 https://en.cppreference.com/w/cpp/language/union

Members of an anonymous union are injected in the enclosing scope (and must not conflict with other names declared there).

改变

struct s2 {
int a;
union u {
    int b;
    double c;
    };
};

struct s2 {
int a;
union u {
    int b;
    double c;
    } x;
};

你会得到相同的尺寸。

您的版本声明了一个内部类型,但没有创建 union u 的实例。

您的 s1 使用匿名联合,它有效地将您的联合实例注入 s1 但没有命名它。

基本上归结为对齐要求。对于 x86,基本类型的对齐要求是根据其大小对齐类型,即 4 字节类型将对齐 4 字节,8 字节类型将对齐 8 字节等。

在 x86 上,class/union 与其最大的原始成员对齐,即如果有 8 字节成员,则 class/union 将对齐 8 字节。

s1 的情况下,我们有一个 anonymous union,它被注入到外部范围(即它成为 s1 的一部分)

struct s1 {
    int a;
    union {
        int b;
        double c;
    };
};

联合体的最大类型是double,8 字节,因此联合体按8 字节对齐。编译器在 a 之后添加 4 个字节的填充以使联合对齐 8 个字节。

我们可以用这个来确认:

cout << offsetof(s1, a) << " " << offsetof(s1, b) << " " << offsetof(s1, c) << endl;

版画

0 8 8

如果s2

union u { ... }; 是一个 声明 。它没有定义 u 类型的元素。所以 s2 只有一个成员 int a; 并且是 4 个字节长。

要将其更改为定义,请为其命名:union u { ... } u;