结构/对象内的存储顺序
考虑这两种情况:
struct customType { dataType1 var1; dataType2 var2; dataType3 var3; } ; customType instance1; // Assume var1, var2 and var3 were initialized to some valid values. customType * instance2 = &instance1; dataType1 firstMemberInsideStruct = (dataType1)(*instance2);
class CustomType { public: dataType1 member1; dataType2 member2; retrunType1 memberFunction1(); private: dataType3 member3; dataType4 member4; retrunType2 memberFunction2(); }; customType object; // Assume member1, member2, member3 and member4 were initialized to some valid values. customType *pointerToAnObject = &object ; dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);
这样做总是安全的吗?
我想知道标准是否指定了任何存储顺序 –
- C结构中的元素。
- C ++类对象内的数据成员。
C99和C ++在这方面略有不同。
C99标准保证结构的字段将按照它们声明的顺序在内存中布局,并且两个相同结构的字段将具有相同的偏移量。 有关C99标准的相关章节,请参阅此问题 。 总结一下:第一个字段的偏移量指定为零,但之后的偏移量未由标准指定。 这是为了允许C编译器调整每个字段的偏移量,以便该字段满足架构的任何内存对齐要求。 因为这是依赖于实现的,所以C提供了一种使用offsetof
宏来确定每个字段的偏移量的标准方法。
C ++仅为普通旧数据(POD)提供此保证。 不是普通旧数据的C ++类不能这样对待。 当该类使用多重inheritance,具有非公共字段或成员或包含虚拟成员时,该标准为C ++编译器提供了组织类的自由度。
这对您的示例意味着什么:
dataType1 firstMemberInsideStruct = (dataType1)(*instance2);
仅当 dataType1,dataType2和dataType3是普通旧数据时,此行才可以。 如果它们中的任何一个不是,那么customType结构可能没有一个简单的构造函数(或析构函数),并且这个假设可能不成立。
dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);
无论dataType1
, dataType2
和dataType3
是否为POD,此行都不安全,因为CustomType
类具有私有实例变量。 这使得它不是 POD类,因此您不能假设它的第一个实例变量将以特定方式排序。
9.0.7
标准布局类是一个类: – 没有非标准布局类(或此类类型的数组)或引用的非静态数据成员, – 没有虚函数(10.3)且没有虚基类( 10.1), – 对所有非静态数据成员具有相同的访问控制(第11条), – 没有非标准布局基类, – 在最派生类中没有非静态数据成员,最多只有一个具有非静态数据成员的基类,或者没有具有非静态数据成员的基类,并且 – 没有与第一个非静态数据成员相同类型的基类。
9.2.14
分配具有相同访问控制(第11条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。 具有不同访问控制的非静态数据成员的分配顺序未指定(11)。 实施对齐要求可能导致两个相邻成员不能立即分配; 因此,可能需要空间来管理虚拟function(10.3)和虚拟基类(10.1)。
9.2.20
指向标准布局结构对象的指针(使用reinterpret_cast进行适当转换)指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 [注意:因此,在标准布局结构对象中可能存在未命名的填充,但不是在其开头,以实现适当的对齐。 – 结束说明]
这样做并不总是安全的。 如果类有virtual
方法,那绝对不是。 保证数据成员对于相同的访问级别块以相同的顺序出现,但是可以对这些组进行重新排序。
为了安全地使用这些类型的强制类型转换,您应该提供转换构造函数或强制转换运算符,而不是依赖于实现细节。
通常在C结构中,成员按声明它们的顺序存储。 但是元素必须正确对齐。 维基百科就是如何运作的一个很好的例子。
我将在这里重复:
如果您有以下结构
struct MixedData { char Data1; short Data2; int Data3; char Data4; };
填充将插入不同数据类型之间,以确保正确的字节对齐。 char
s是1字节对齐的, short
s是2字节对齐的, int
是4字节对齐的等等。
因此,为了使Data2
2字节对齐,将在Data1
和Data2
之间插入1字节填充。
还值得一提的是,存在可以改变包装对齐的机制。 请参阅#pragma pack 。