结构对齐和类型重新解释

Struct alignment and type reinterpretation

假设我有两种类型 A 和 B。

那我做这个

struct Pair{
    A a;
    B b;
};

现在我有了这样的功能。

void function(Pair& pair);

并假设 function 只会使用该对的 a 部分。

那么这样使用调用函数是不是未定义行为?

A a;
function(reinterpret_cast<Pair&>(a));

我知道编译器可能会在成员之后插入填充字节,但它也可以在第一个成员之前插入吗?

是的,这是未定义的行为。

在一个结构对中,a和b之间可以有填充。对结构成员的赋值可以修改结构中的任何填充。因此,对 pair.a 的赋值可以修改它认为结构中存在填充的内存,而实际上,在您的 a 占用的内存之后只有随机内存。

我认为这是定义的行为,假设 Pair 是标准布局。否则,它是未定义的行为。

首先,一个标准布局 class 和它的第一个成员共享一个地址。 [basic.compound] 中的新措辞(澄清了之前的规则)如下:

Two objects a and b are pointer-interconvertible if:
* [...]
* one is a standard-layout class object and the other is the first non-static data member of that object, or, [...]
* [...]
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast (5.2.10).

也来自[class.mem]:

If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any).

所以 reinterpret_castAPair 没问题。如果 function 只访问 a 对象,那么该访问是明确定义的,因为 A 的偏移量是 0,所以行为等同于让 function 采取一个 A& 直接。显然,对 b 的任何访问都是未定义的。


但是,虽然我相信代码是定义的行为,但这是个坏主意。它定义了 现在 的行为,但有一天可能有人会更改 function 以引用 pair.b,然后你就会陷入痛苦的世界。简单地写一下会容易得多:

void function(A& a) { ... }
void function(Pair& p) { function(p.a); }

然后直接用您的 a 调用 function