2013-12-18 41 views
4

我们知道,有在A大小的不同,当你定义A这样的:内存对齐优化也是内存大小

class A 
{ 
    short a; 
    double b; 
    short c; 
}; 

或类似这样的

class A 
{ 
    short a; 
    short c; 
    double b; 
}; 

我假设我们正在编译32位操作系统,并且我们告诉编译器对齐到32位。

编译器是否真的很难通过实现相同的性能来重新排序定义以获得最小大小?

+0

使用'__attribute__((__packed __))' – Mine

+0

这是我想要的解决方案吗?这是不是这样的大小问题?默认选项?(如果不是,那么为什么?如果是,那么谢谢:)!) – Narek

+2

还要考虑多模块编译的后果。如果一个模块重新排序而另一个模块不重新排序 – Mysticial

回答

4

这是非常困难的。特别需要一个结构来按照与结构定义完全相同的顺序排列字段。

这个要求可能是对帕斯卡没有这样的要求和造成令人惊讶的结果的反应。

无论如何,并非所有的CPU架构都需要对齐或填充。在大多数情况下,它会导致轻微的性能损失。在现代处理器的时代,由于CPU管道的其他方面,内存提取中额外的一个或两个周期可能会消失。

+0

我同意大部分答案,而不是“额外的一个或两个周期”:有些处理器根本不支持不对齐的提取,因此如果使用'__attribute __(),则需要多指令序列来访问未对齐的字段。 (__packed __))'结构。对齐是有原因的。另外,如果结构打包在需要对齐的体系结构上,则无法可靠地采用指向结构成员的指针。 –

+0

@JoeZ:我记得68000非常适合它恼人的未对齐内存陷阱。幸运的是,这些限制在现代CPU中越来越不常见。即使8086也不会因未对齐的16位访问而发生故障:只需花费更长的时间。如果您想充分利用5 MHz扬声器,那么您可以对齐这些词。 – wallyk

+0

x86处理器处理不对齐,当然。 ARM处理器不会启用适当的功能位。 (至少对于ARMv7来说就是这样。)如果尝试在错误的对齐边界加载SSE类型,我相信即使是x86错误。 –

1

不难为编译器,它是由标准方式禁止(有一个例外): 第9.2.12:(非联合)的

非静态数据成员类没有声明 中间访问说明符被分配,以便后面的成员在类对象中具有更高的地址 。的由接入说明符分离 非静态数据成员分配的顺序是不确定的

例外是,具有不同的访问修饰符成员可以是reorderes这样:

class A 
{ 
public: 
    int a; 
    int b; 
private: 
    int c; 
int d; 
{'\; 

a和b,无法重新排序。 c和d不能重新排序,但(a和b)可以重新排序(c和d)

0

由于标准的要求(粗略地说:唯一的,递增的地址和分组的C++类,编译器无法重新排序通过访问修饰符)。

这就是为什么重新排序需要手工完成。 通常,您在这里很幸运:现有数据类型的更好对齐意味着更小的尺寸和更好的性能,这里没有任何限制。

但是,有时较大的数据(元素)大小意味着更简单的指令。例如,使用位字段来削减几个字节意味着更复杂的代码,代码大小和数据大小之间存在折衷;将内部循环增加500字节以削减2k数据对于代码的优化和内存局部性可能是灾难性的。

像PVS Studio这样的工具可以发出警告当结构元素顺序不是最理想的并且可以改进时。


[EDIT2]至于“为什么这些规则的存在”

TL;博士:这是有趣的,但并不重要,它只是好奇着想。

优先(从另一无情拷贝SO回答)的标准的相关部分:

内的结构对象,非位字段构件和单元,其中位字段驻留有地址即增加他们宣布的顺序。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位域,则指向它所在的单位),反之亦然。结构对象中可能有未命名的填充,但不在其开头。

指向标准布局结构对象的指针,适当地使用reinterpret_cast进行转换,指向其初始成员(或者如果该成员是位字段,则指向其驻留的单元),反之亦然。 [注意:因此在标准布局结构对象中可能存在未命名的填充,但在开始时并不需要填充,以实现适当的对齐。末端注]

(请注意,这涉及到C,C++是更复杂一点。)

的标准说一点关于原因,大多是 “猜测” 在这里:

独特的地址是由标准的其他问题产生的要求。

制作指向结构类型转换的指针 - 等价于指向第一个成员的指针当然是由于现有的编程习惯。 (它允许“数据polymorphy”用C通过嵌套“基地结构”为“衍生结构”的第一部件)由程序员指定

保留的顺序

的“香草猜测”不会破坏数据局部的手工优化。将最常访问的成员置于顶层可以改善结构中的局部性(允许更好的缓存或更短的寻址指令)。如果编译器重新排序,那么对于总体结构大小相对小的增益,这些优化可能会丢失。

C++需要通过访问说明分组:(即“所有公共瓦尔在一起,所有受保护的乏在一起,所有的私人瓦尔在一起):我从来没有发现一个理由(我必须说,它是一个有点出人意料)我可以想象,(可能)意图是允许编译器实现利用硬件访问控制(“这段代码可能无法访问那块内存”)。OTOH我知道没有任何体系结构可以使得控制,我从来没有见过访问说明符被认为是一个安全的机制。

+0

我在哪里可以阅读更多关于标准的这些要求的原因? – Narek