结构/对象内的存储顺序



考虑以下两种情况:

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++类对象内的数据成员。

C99和C++在这方面略有不同。

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

C++仅为普通旧数据 (POD) 提供此保证。 C++不是纯旧数据的类不能这样处理。 当类使用多重继承、具有非公共字段或成员或包含虚拟成员时,该标准为C++编译器提供了相当大的自由度来组织类。

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

dataType1 firstMemberInsideStruct = (dataType1)(*instance2);

仅当数据类型 1、数据类型 2 和数据类型 3 是纯旧数据时,此行才有效。 如果它们中的任何一个不是,则 customType 结构可能没有简单的构造函数(或析构函数),并且此假设可能不成立。

dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);

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

9.0.7

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

9.2.14

具有相同访问权限的(非联合)类的非静态数据成员 控制权(第11条)被分配,以便后来的成员有更高的 类对象中的地址。非静态的分配顺序 未指定具有不同访问控制的数据成员 (11)。 实现对齐要求可能会导致两个相邻的成员 不要紧紧分配;所以可能 管理虚拟功能的空间要求 (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 s 是 4 字节对齐的,依此类推。

因此,为了使Data2 2 字节对齐,将在 Data1Data2 之间插入一个 1 字节填充。

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

最新更新