6

考虑这两种情况:

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

4 回答 4

7

C99 和 C++ 在这一点上有所不同。

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

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

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

dataType1 firstMemberInsideStruct = (dataType1)(*instance2);

仅当dataType1、dataType2 和 dataType3 是普通旧数据时,此行才可以。如果其中任何一个都不是,那么 customType 结构可能没有普通的构造函数(或析构函数),并且这个假设可能不成立。

dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);

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

于 2012-07-05T08:28:01.053 回答
6

9.0.7

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

9.2.14

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

9.2.20

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

于 2012-07-05T08:01:55.427 回答
1

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

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

于 2012-07-05T07:55:27.753 回答
0

通常在 C 结构中,成员按照声明的顺序存储。但是元素必须正确对齐。维基百科有一个很好的例子来说明这是如何工作的。

我将在这里重申:

如果你有以下结构

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

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

因此,为了使Data22 字节对齐,将在Data1和之间插入一个 1 字节填充Data2

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

于 2012-07-05T07:53:49.030 回答