我的理解是,如果要对齐数组,必须明确指定数组的对齐方式。
但是,我声明的浮点数组似乎总是与16字节对齐。
float *ptr1 = new float[1];
cout<<"ptr1: "<<ptr1<<endl;
float *ptr2 = new float[3];
cout<<"ptr2: "<<ptr2<<endl;
float arr1[7];
cout<<"arr1: "<<arr1<<endl;
float arr2[9] __attribute__((aligned(2)));
cout<<"arr2: "<<arr2<<endl;
这是输出
ptr1: 0x13dc010
ptr2: 0x13dc030
arr1: 0x7fff874885c0
arr2: 0x7fff87488590
这有什么理由吗?我正在使用gcc 4.6.3
但是,如果它是指向浮点位置或静态分配的指针,我看不到它
static float arr3[9] __attribute__((aligned(2)));
cout<<"arr3: "<<arr3<<endl;
float *x;
cout<<"x: "<<x<<endl;
输出:
arr3: 0x4030b2
x: 0x7fff8c7dd9e8
此代码在x64上运行。
答案 0 :(得分:4)
对齐要求由每个编译器确定,受硬件要求的影响。
C和C ++语言讨论了类型的对齐,但它们没有强加任何特定的要求(例如,结构的对齐至少是其任何成员的对齐)。有效的实现可以允许所有数据类型进行字节对齐,或者可能要求每个标量类型与其自己的大小对齐(后者更常见)。中间对齐是可能的,例如在4字节边界上对齐8字节类型。
特别是在x86上,将标量与其大小对齐可以提高访问效率,但是错位访问仍然可以正常工作,但速度要慢一点。
float
数组的必需对齐方式与单个float
对象所需的对齐方式相同。如果float
是4个字节,那么该对齐不能超过4个字节,因为数组之间没有间隙。
特定编译器可能会选择对数组对象进行更严格的对齐,就像您(可能)看到的那样,如果它能够更有效地访问这些对象。
如果通过调用new
来实现malloc
运算符,则所有new
- 分配的对象将具有足够严格的对齐任何类型。
如果float
数组始终与16字节边界对齐,那是因为编译器选择以这种方式分配它们,而不是因为语言需要它。另一方面,如果使用别名强制float
数组为4字节对齐(假设为sizeof (float) == 4
),则对该数组及其元素的访问仍应正常工作。
顺便提一下,当我在x86_64系统上运行你的代码(在main
程序中包装它之后)后,我得到的结果与你的类似。当我在x86系统上运行它时,我得到:
ptr1: 0x9e34008
ptr2: 0x9e34018
arr1: 0xbfefa160
arr2: 0xbfefa17c
我在两个系统上使用Linux下的gcc。
因此,您问题的直截了当的答案是否定的,float
数组并不总是与16字节边界对齐。
但在大多数情况下,没有特别理由让你关心。除非您使用别名技巧(将某些声明类型的对象视为另一种类型),否则编译器将始终为每个对象提供正确访问所需的对齐。
答案 1 :(得分:1)
我不确定我是否完全理解这个问题,但如果你想要更大的尺寸,我建议使用“double”类型而不是“float”。 “Float”的大小限制通常为4个字节(约7位),而“double”的大小限制通常为8个字节(约15个数字)。
编辑:对不起,我误解了这个问题答案 2 :(得分:0)
这取决于平台的最严格的基本类型对齐要求,如long double,这是我的Debian 64系统需要的16字节对齐。 堆栈帧对齐也可能受此影响。