字符数组的对齐方式

6
STL vector通常是如何实现的?它具有char[]的原始存储,偶尔会按一定因素调整大小,然后在push_back元素时调用放置new(我应该指出的是非常有趣的语法形式-语言学家应该研究这样的动词形式,即pushed_back :))。然后有对齐要求。因此,一个自然的问题就出现了:如何在char[]上调用放置new并确保满足对齐要求?所以我搜索了2003年的C++标准中单词“alignment”,找到了以下内容:
段落3.9条款5
对象类型具有对齐要求(3.9.1、3.9.2)。完整对象类型的对齐方式是一个表示字节数的实现定义整数值;对象分配在满足其对象类型的对齐要求的地址上。
段落5.3.4条款10:
新表达式将请求的空间量作为std::size_t类型的第一个参数传递给分配函数。该参数不得小于正在创建的对象的大小;仅当对象是数组时,它可能大于正在创建的对象的大小。对于char和unsigned char数组,新表达式的结果与分配函数返回的地址之间的差异应该是任何大小不大于正在创建的数组的任何对象类型最严格对齐要求(3.9)的整数倍。[注意:因为假定分配函数返回适当对齐于任何类型的对象的存储指针,所以数组分配开销的这个限制允许将字符数组分配到稍后将放置其他类型对象的地方。]
这两个给出了我上述问题的完全令人满意的答案,但是...
声明1:
X类型对象的对齐要求,其中sizeof(X) == n,至少是X地址可被n整除或类似的东西(将所有架构相关的东西放入“或类似的东西”中)。
问题1:请确认、完善或否认上述声明1。
声明2:如果声明1正确,则从标准中的第二个引用可以得出结论:5000000个字符的数组在可被5000000整除的地址处分配,这对我只需要char数组本身而不是作为可能放置其他对象的原始存储来说是完全不必要的。
问题2:那么,成功分配1000个字符的机会是否真的比500个shorts(如果short是2字节)低?这在实践中是一个问题吗?
3个回答

4
当你使用operator new动态分配内存时,你有保证:
返回的指针将被适当地对齐,以便可以将其转换为任何完整对象类型的指针,然后用于访问存储分配的对象或数组(直到通过调用相应的释放函数显式释放存储)(C++03 3.7.3.1/2)。 vector不创建字符数组;它使用一个分配器。默认分配器使用::operator new来分配内存。

3
当sizeof(X) == n时,类型X的对齐要求至少是X的地址可被n整除或类似的要求。
不一定。类型的对齐要求始终是其大小的因数,但不一定等于其大小。通常等于类中所有成员的对齐要求中最大的那个。
一个包含5M个字符的数组仅需要具有1的对齐要求,与单个char的对齐要求相同。
因此,你引用的有关通过全局运算符new分配的内存的对齐的文本(malloc具有类似但不完全相同的要求),实际上意味着大量分配必须遵守系统中任何类型的最严格的对齐要求。此外,实现通常会将大型SIMD类型排除在外,并要求专门分配用于SIMD的内存。这有点可疑,但我认为他们的理由是非标准扩展类型可以强加任意特殊要求。
因此,在实践中,你认为是5000000的数字通常是4 :-)

1

问题1:对齐与大小无关。

问题2:理论上是可以的,但你很难找到一种具有如此巨大对齐的类型的架构。SSE需要16字节对齐(我见过的最大对齐要求)。


@Let_Me_Be:我认为对齐与大小有关的原因是,如果我取一个X数组,所有的X都应该遵守对齐要求,那么地址a、a+sizeof(X)、a+2*sizeof(X)等等都应该符合这些要求。这就导致了我定义这个语句。我错了吗? - Armen Tsirunyan
@jalf:即使是纯粹主义者也会同意一个字符始终是一个字节 :) 但他们会争论这是多少位 :)) 现在,我明白你说的了。那么,new(p+sizeof(someComplexStruct)) someComplexSttruct呢?这肯定是合法的,但我不明白为什么。 - Armen Tsirunyan
@Armen:不会的。;) char 没有被定义为任何特定数量的字节。它只是 C++ 中用于寻址内存的最小单元。但是,例如,char 可以是 2 或 4 个字节。 - jalf
1
@jalf 标准实际上将 char 称为 byte,但没有指定每个字节的位数。我倾向于称其为 C-byte。 - Šimon Tóth
1
@jalf: C++ 2003 Par 5.3.3第1条款 sizeof运算符返回其操作数的对象表示中的字节数。 操作数可以是未计算的表达式或带括号的类型标识符。 sizeof运算符不得应用于具有函数或不完整类型的表达式,或在声明其所有枚举器之前应用于枚举类型,或应用于此类类型的带括号的名称,或指定位域的左值。 sizeof(char),sizeof(signed char)和sizeof(unsigned char)均为1; - Armen Tsirunyan
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接