我今天遇到的代码类似于以下代码,我很好奇实际发生了什么:
#pragma pack(1)
__align(2) static unsigned char multi_array[7][24] = { 0 };
__align(2) static unsigned char another_multi_array[7][24] = { 0 };
#pragma pack()
在Keil编译器中搜索__align关键字的引用时,我遇到了这个:
执行区域和输入部分的总计在某些情况下,您需要对代码和数据部分进行操作...如果您可以访问原始源代码,则可以在编译时使用__align(n)关键字......
我不明白“overaligning代码和数据部分”的含义。有人可以帮助澄清这种调整是如何发生的吗?
答案 0 :(得分:6)
编译器自然会根据系统的需要“对齐”数据。例如,在典型的32位系统中,32位整数应始终为单个4字节字(而不是部分在一个字中,部分在下一个字中),因此它总是从4开始字节边界。 (这主要与处理器上可用的指令有关。系统很可能有一条指令将一个字从存储器加载到一个寄存器中,并且很可能只有一条指令来加载一个任意的四个序列相邻的字节进入寄存器。)
编译器通常通过在数据中引入间隙来实现此目的;例如,在这样的系统上,struct
带有char
后跟32位int
,需要8个字节:char
一个字节,三个字节填充因此int
对齐,int
本身对齐四个字节。
要“overalign”数据是为了请求比编译器自然提供的更大的对齐。例如,您可以请求在8字节边界上开始32位整数,即使在使用4字节字的系统上也是如此。 (执行此操作的一个主要原因是,如果您的目标是使用8字节字的系统进行字节级互操作:如果将struct
从一个系统传递到另一个系统,则需要相同的间隙在两个系统中。)
答案 1 :(得分:5)
通过overalign,Keil意味着没有比将对象与更大的对齐边界对齐而不是数据类型所需的更复杂。
请参阅__align的文档:“您只能对其进行操作。也就是说,您可以将两个字节的对象设置为四字节对齐,但不能将两个字节的四字节对象对齐。”
对于链接器,您可以使用ALIGNALL
或OVERALIGN
指令强制在其他二进制模块中的部分上进行额外的对齐。出于性能原因,这可能很有用,但不是常见的情况。
答案 2 :(得分:4)
对齐是指数据的对齐方式超过其默认对齐方式。例如,4字节int
通常具有4字节的默认对齐。 (意思是地址可以被4整除)
数据类型的默认对齐方式通常(但不总是)是数据类型的大小。
Overalignment允许您将此对齐增加到大于默认值的值。
至于您为什么要这样做:
这样做的一个原因是能够使用更大的数据类型(具有更大的对齐)访问数据。
例如:
char buffer[16];
int *ptr = (int*)&buffer;
ptr[0] = 1;
ptr[1] = 2;
默认情况下,缓冲区仅对齐1个字节。但是,int
需要4字节对齐。如果buffer
未与4个字节对齐,则会出现未对齐异常。 (AFAIK,ARM不允许未对齐的内存访问... x86 / 64通常会这样做,但性能下降)
__align()
会让你强行对齐以使其正常工作:
__align(4) char buffer[16];
使用SIMD指令时会出现类似情况。您将访问具有大型SIMD数据类型的较小数据类型 - 这可能需要更大的对齐。