Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有单个基元类型数组成员的标准布局结构的保证内存布局_C++_Language Lawyer_Memory Layout_Standard Layout - Fatal编程技术网

C++ 具有单个基元类型数组成员的标准布局结构的保证内存布局

C++ 具有单个基元类型数组成员的标准布局结构的保证内存布局,c++,language-lawyer,memory-layout,standard-layout,C++,Language Lawyer,Memory Layout,Standard Layout,考虑以下简单结构: struct A { float data[16]; }; 我的问题是: 是32位IEEE74浮点数(如果有问题),C++标准是否保证了结构A < /代码>的预期内存布局?如果没有,它保证什么和/或执行保证的方式是什么 通过预期内存布局,我的意思是结构占用内存中的16*4=64字节,每个连续的4字节由数据数组中的单个浮点占用。换句话说,预期内存布局意味着以下测试通过: static_assert(sizeof(A) == 16 * sizeof(float)); s

考虑以下简单结构:

struct A
{
    float data[16];
};
我的问题是: <假设一个平台,代码<浮动> /COD>是32位IEEE74浮点数(如果有问题),C++标准是否保证了<代码>结构A < /代码>的预期内存布局?如果没有,它保证什么和/或执行保证的方式是什么

通过预期内存布局,我的意思是结构占用内存中的
16*4=64
字节,每个连续的
4
字节由
数据
数组中的单个
浮点
占用。换句话说,预期内存布局意味着以下测试通过:

static_assert(sizeof(A) == 16 * sizeof(float));
static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
...
static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
offset of
在这里是合法的,因为
A
是标准布局,见下文)

如果您对此感到不安,请在带有gcc 9头的魔杖盒上进行测试。我从来没有遇到过平台和编译器的组合,它们可以提供这个测试可能失败的证据,如果它们确实存在的话,我很想了解它们

为什么人们会关心:
  • 类似SSE的优化需要特定的内存布局(和对齐,我在这个问题中忽略了这一点,因为它可以使用标准的
    alignas
    说明符来处理)
  • 这种结构的序列化可以简单地归结为一个好的、可移植的
    写字节(&x,sizeof(a))
  • 一些API(例如OpenGL,具体地说)期望这种精确的内存布局。当然,只需将指针传递到
    数据
    数组,即可传递此类型的单个对象,但对于这些对象的序列(例如,用于上载矩阵类型顶点属性),仍然需要特定的内存布局
实际保证的是: 据我所知,这些是可以从
struct A
中得到的:

  • 是的
  • 作为标准布局的结果,指向
    a
    的指针可以
    重新解释为指向其第一个数据成员的指针(可能是
    data[0]
    ?),即在第一个成员之前没有填充
据我所知,本标准提供的其余两项担保为:

  • 在基元类型数组的元素之间没有填充(我确信这是错误的,但我没有找到确认引用)
  • struct A
    中的
    data
    数组之后没有填充

    • 关于布局,有一件事是不能保证的,即多字节对象中的字节顺序<代码>写入字节(&x,sizeof(A))不是跨具有不同端号的系统的可移植序列化

      A
      可以
      重新解释\u cast
      到指向其第一个数据成员的指针(可能是
      数据[0]
      ?)

      更正:第一个数据成员是
      data
      ,您可以使用它重新解释强制转换。至关重要的是,数组与其第一个元素的指针不可相互转换,因此不能重新解释它们之间的强制转换。然而,地址保证是相同的,所以据我所知,在
      std::launder
      之后重新解释为
      data[0]
      应该没问题

      基元类型数组的元素之间没有填充

      数组保证是连续的<对象的code>sizeof是根据将元素放入数组所需的填充来指定的
      sizeof(T[10])
      的大小正好是
      sizeof(T)*10
      。如果相邻元素的非填充位之间存在填充,则该填充位于元素本身的末尾

      基本类型一般不保证没有填充。例如,x86扩展精度
      长双精度
      为80位,填充为128位

      char
      signed char
      unsigned char
      保证没有填充位。C标准(在此例中C++代表了规范)保证了固定宽度<代码> Inntt和 Untnnt别名没有填充位。在不可能的系统上,不提供这些固定宽度类型

      如果标准布局类对象具有任何非静态数据成员,则其 地址与其第一个非静态数据成员的地址相同。 否则,其地址与第一个基址的地址相同 类子对象(如果有)。[注:因此,标准布局结构对象中可能会有未命名的填充,但不会在其开头,这是实现适当对齐所必需的。-结束注]

      因此,标准保证:

      static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
      
      数组类型的对象包含连续分配的非空 类型为T的N个子对象的集合

      因此,以下是正确的

      static_assert(offsetof(A, data[0]) == 0 * sizeof(float));
      static_assert(offsetof(A, data[1]) == 1 * sizeof(float));
      ...
      static_assert(offsetof(A, data[15]) == 15 * sizeof(float));
      

      剩下的保证中的第一个是由C++ 2017(草案n469)113.4保证的,“数组”[dCL,数组]:“数组类型的对象包含一个连续分配的非空集合的<代码> n< /代码>类型<代码> t>代码> 1998版本具有相同的文本,除了连字符的子对象”。在8.3.4中,谢谢您的澄清!“连续分配”在本文中的确切含义是什么?@lisyarus:它是“普通英语”,或者至少是标准中没有正式定义的领域从业人员使用的英语。我很确定这意味着数组中元素的字节一个接一个地排列在内存中,元素之间没有填充。在C中,剩余的第二个保证是不保证的,并且有一些原因导致“困难”的C实现可能填充包含单个数组的结构。例如,我们可以想象,如果一个实现的目标硬件非常倾向于四个字节,那么它将把
      struct{char x[2];}
      填充到四个字节