结构/对象内的存储顺序

时间:2012-07-05 07:52:09

标签: c++ c class pointers structure

考虑以下两种情况:

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);

总是安全吗?

我想知道标准是否指定了 -

之间的任何存储顺序
  1. C结构中的元素。
  2. C ++类对象内的数据成员。

4 个答案:

答案 0 :(得分:6)

9.0.7

  

标准布局类是一个类: - 没有非静态数据   类型为非标准布局类的成员(或此类类型的数组)或   参考, - 没有虚函数(10.3),没有虚拟基础   类(10.1), - 对所有人具有相同的访问控制(第11条)   非静态数据成员, - 没有非标准布局基类, -   要么在大多数派生类中都没有非静态数据成员   大多数基类具有非静态数据成员,或者没有基础   具有非静态数据成员的类,以及 - 没有基类   与第一个非静态数据成员相同的类型.108

9.2.14

  

具有相同访问权限的(非联合)类的非静态数据成员   控制(第11条)被分配,以便后来的成员有更高的   类对象中的地址。非静态分配的顺序   具有不同访问控制的数据成员未指定(11)。   实现对齐要求可能会导致两个相邻成员   不要在对方之后立即分配;可能   管理虚拟功能的空间要求(10.3)和   虚基类(10.1)。

9.2.20

  

指向标准布局结构对象的指针,适当地使用转换   reinterpret_cast指向其初始成员(或者如果该成员是   比特字段,然后到它所在的单元,反之亦然。 [   注意:因此可能有一个未命名的填充   标准布局结构对象,但必要时不在其开头   实现适当的对齐。 - 结束说明]

答案 1 :(得分:4)

C99和C ++对此有所不同。

C99标准保证结构的字段将按照它们声明的顺序在内存中布局,并且两个相同结构的字段将具有相同的偏移量。有关C99标准的相关章节,请参阅this question。总结一下:第一个字段的偏移量指定为零,但之后的偏移量未由标准指定。这是为了允许C编译器调整每个字段的偏移量,以便该字段满足架构的任何内存对齐要求。因为这是依赖于实现的,所以C提供了一种使用offsetof宏来确定每个字段的偏移量的标准方法。

C ++仅为Plain old data (POD)提供此保证。不是普通旧数据的C ++类不能这样对待。该标准为C ++编译器在类使用多重继承,非公共字段或成员或包含虚拟成员时如何组织类提供了相当大的自由。

这对您的示例意味着什么:

dataType1 firstMemberInsideStruct = (dataType1)(*instance2);

只有当 dataType1,dataType2和dataType3是纯旧数据时,此行才可以。如果它们中的任何一个不是,那么customType结构可能没有一个简单的构造函数(或析构函数),并且这个假设可能不成立。

dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);

无论dataType1dataType2dataType3是否为POD,此行都不安全,因为CustomType类具有私有实例变量。这使得成为POD类,因此您不能假设它的第一个实例变量将以特定方式排序。

答案 2 :(得分:1)

这样做并不总是安全的。如果类具有virtual方法,则绝对不是。保证数据成员对同一访问级别块的顺序相同,但可以重新排序这些组。

为了安全使用这些类型的强制转换,您应该提供转换构造函数或强制转换运算符,而不是依赖于实现细节。

答案 3 :(得分:0)

通常在C结构中,成员按声明的顺序存储。但是元素必须正确对齐。维基百科有一个how this works的好例子。

我将在这里重复:

如果您有以下结构

struct MixedData
{
    char Data1;
    short Data2;
    int Data3;
    char Data4;
};

将在不同数据类型之间插入填充,以确保正确的字节对齐。 char是1字节对齐的,short是2字节对齐的,int是4字节对齐的等等。

因此,要使Data2 2字节对齐,Data1Data2之间将插入1字节填充。

还值得一提的是,有一些机制可以改变包装对齐方式。请参阅#pragma pack