【问题标题】:Alignment of char arrays字符数组的对齐
【发布时间】:2011-04-29 21:31:09
【问题描述】:

STL向量通常是如何实现的?它有一个 char[] 的原始存储,它偶尔会按某个因素调整大小,然后在元素被 push_back 时调用placement new(我应该注意一个非常有趣的语法形式 - 语言学家应该研究诸如 push_back 之类的动词形式:)
然后是对齐要求。所以一个自然的问题出现了,我如何在 char[] 上调用一个新的位置并确保满足对齐要求。所以我在 2003 年的 C++ 标准中搜索了“对齐”这个词,发现了这些:

第 3.9 条第 5 条

对象类型有对齐要求(3.9.1、3.9.2)。完整对象类型的对齐方式是实现定义的整数值,表示字节数;对象分配在满足其对象类型对齐要求的地址。

第 5.3.4 条第 10 条:

new 表达式将请求的空间量作为 std::size_t 类型的第一个参数传递给分配函数。该参数不应小于正在创建的对象的大小;只有当对象是一个数组时,它才可能大于正在创建的对象的大小。对于 char 和 unsigned char 数组,new-expression 的结果与分配函数返回的地址之间的差应是任何大小不大于正在创建的数组的大小。 [注意:因为分配函数被假定返回指向为任何类型的对象适当对齐的存储的指针,所以对数组分配开销的这种约束允许分配字符数组的常见习惯用法,稍后将在其中放置其他类型的对象。 ]

这两个对我上面的问题给出了一个非常令人满意的答案,但是......

声明1:
X 类型对象的对齐要求,其中 sizeof(X) == n 至少要求 X 的地址可以被 n 整除或类似的东西(将所有与架构相关的东西放入“或类似的东西”中)。

问题1:请确认、完善或否认上述说法1。

Statement2:如果 statement1 是正确的,那么从标准中的第二个引用可以看出,在可被 5000000 整除的地址处分配了一个 5000000 个字符的数组,如果我只需要这样的 char 数组而不是用于可能放置其他对象的原始存储。

问题 2: 那么,成功分配 1000 个字符的机会真的低于 500 个 shorts(假设 short 是 2 个字节)吗?这实际上是一个问题吗?

【问题讨论】:

    标签: c++ alignment


    【解决方案1】:

    当您使用operator new 动态分配内存时,您可以保证:

    返回的指针应适当对齐,以便它可以转换为任何完整对象类型的指针,然后用于访问分配的存储中的对象或数组(直到通过调用相应的存储显式释放存储)释放函数)(C++03 3.7.3.1/2)。

    vector 不创建 char 数组;它使用分配器。默认分配器使用::operator new 分配内存。

    【讨论】:

      【解决方案2】:

      对象的对齐要求 X 类型,其中 sizeof(X) == n 位于 至少要求的地址 X 可以被 n 整除或类似的东西 那个

      没有。类型的对齐要求始终是其大小的一个因素,但不必等于其大小。它通常等于类中所有成员的最大对齐要求。

      一个5M char的数组,就其本身而言,只需要对齐要求为1,与单个char的对齐要求相同。

      因此,您引用的关于通过全局运算符new 分配的内存对齐的文本(和malloc 具有类似的尽管 IIRC 不相同的要求)实际上意味着大分配必须遵守最严格的对齐要求系统中的任何类型。此外,实现通常会从中排除大型 SIMD 类型,并要求专门为 SIMD 分配内存。这有点可疑,但我认为他们的理由是非标准的扩展类型可以强加任意特殊要求。

      所以实际上你认为是 5000000 的数字通常是 4 :-)

      【讨论】:

        【解决方案3】:

        Q1:对齐与大小无关。

        Q2:理论上是的,但是你很难找到一个具有如此大对齐类型的架构。 SSE 需要 16 字节对齐(我见过的最大的)。

        【讨论】:

        • @Let_Me_Be:我认为对齐 is 与大小相关的原因是,如果我采用一个 X 数组并且它们都应该遵守对齐要求,那么地址 a , a+sizeof(X), a+2*sizeof(X) ...等都应该符合这些要求。这导致我定义了这个陈述。我错了吗?
        • @Armen:你搞错了。对象的大小必须是其对齐方式的倍数。 char 通常具有对齐 1,int 通常必须在 4 字节边界上对齐。包含两者的struct 被赋予其最严格对齐的成员的对齐方式(因此,如果它包含charint,则整个结构需要与int 相同的对齐方式)。对象的大小也必须是 int 的倍数。对于您的巨大 char 数组也是如此。它只包含字符,每个字符都可以放在任何字节(任何可被 1 整除的地址)
        • 所以数组作为一个整体具有相同的对齐要求(并且还必须是 1 的倍数,这并不难实现。;))
        • @jalf 该标准实际上将char 称为byte,但没有指定每个字节的位数。我倾向于称它为 C 字节。
        • @jalf: C++ 2003 Par 5.3.3 Clause 1 sizeof 运算符在其操作数的对象表示中产生字节数。操作数要么是一个未计算的表达式,要么是一个带括号的类型 ID。 sizeof 运算符不应应用于具有函数或不完整类型的表达式,或应用于在其所有枚举数都已声明之前的枚举类型,或应用于此类类型的括号名称,或应用于指定位域的左值。 sizeof(char)、sizeof(signed char)和sizeof(unsigned char)都是1;
        猜你喜欢
        • 2016-12-15
        • 1970-01-01
        • 2011-02-18
        • 1970-01-01
        • 2014-05-08
        • 1970-01-01
        • 1970-01-01
        • 2015-05-20
        • 2019-10-19
        相关资源
        最近更新 更多