32

在 c/c++ 中(我假设它们在这方面是相同的),如果我有以下内容:

struct S {
  T a;
  .
  .
  .
} s;

下面的内容能保证是真的吗?

(void*)&s == (void*)&s.a;

或者换句话说,是否有任何保证在第一个成员之前不会有填充?

4

2 回答 2

45

在 C 中,是的,它们是相同的地址。简单,直接。


在 C++ 中,不,它们不是同一个地址。基类可以(而且我怀疑,确实)出现在所有成员之前,并且虚拟成员函数通常会在某处将隐藏数据添加到结构中。更令人困惑的是,C++ 编译器还可以随意重新排列成员,除非该类是标准布局类型(尽管我不知道任何编译器都会这样做)

最后,如果 C++ 结构由标准布局类型组成,不包含基类或虚函数,并且所有成员都具有相同的可见性,并且可能我忘记了其他限制,那么它会退回到 C 规则,并要求第一个成员与对象本身位于同一地址。

§ 9.2/7

标准布局类是这样的类:
— 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
— 没有虚拟函数 (10.3) 并且没有虚拟基类 ( 10.1),
— 对所有非静态数据成员具有相同的访问控制(第 11 条),
— 没有非标准布局基类,
— 在最派生的类中没有非静态数据成员,并且最多一个具有非静态数据成员的基类,或没有具有非静态数据成员的基类,并且
- 没有与第一个非静态数据成员相同类型的基类。

§ 9.2/20

指向标准布局结构对象的指针,使用 reinterpret_cast 适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。[注意:因此,标准布局结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。——尾注]

于 2013-07-24T21:30:20.287 回答
16

是的。

保证在 C 和 C++ 中的第一个结构成员之前没有填充(如果它是 POD)。

C报价:

(C11,6.7.2.1p15)“结构对象中可能有未命名的填充,但不是在其开头。”

C++ 引用:

(C++11, 9.2p20) “因此,标准布局结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的”

于 2013-07-24T21:28:39.293 回答