我今天遇到的代码类似于以下代码,我很好奇实际发生了什么:
#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()
Run Code Online (Sandbox Code Playgroud)
当在Keil编译器中搜索对__align关键字的引用时,我遇到了这个:
执行区域和输入部分的总结 在某些情况下,您需要对代码和数据部分进行操作...如果您可以访问原始源代码,则可以在编译时使用__align(n)关键字执行此操作...
我不明白"overaligning代码和数据部分"的含义.有人可以帮助澄清这种运动的发生方式吗?
编译器自然会根据系统的需要"对齐"数据.例如,在典型的32位系统中,32位整数应始终为单个4字节字(而不是部分在一个字中,部分在下一个字中),因此它总是从4开始字节边界.(这主要与处理器上可用的指令有关.系统很可能有一条指令将一个字从存储器加载到一个寄存器中,并且更不可能有一条指令加载一个任意的四个序列邻接字节到寄存器.)
编译器通常通过在数据中引入间隙来实现这一点; 例如,在这样的系统上,struct
a char
后跟32位int
,需要8个字节:char
填充三个字节的一个字节,因此int
右对齐,int
自身为四个字节.
要"完成"数据是为了请求比编译器自然提供的更大的对齐.例如,您可以请求在8字节边界上开始32位整数,即使在使用4字节字的系统上也是如此.(这样做的一个主要原因是,如果您的目标是使用8字节字的系统进行字节级互操作:如果将struct
s从一个系统传递到另一个系统,则需要两个系统中的相同间隙.)
过度对齐是指数据的对齐方式超过其默认对齐方式。例如,4 字节int
通常具有 4 字节的默认对齐方式。(意味着地址将被 4 整除)
数据类型的默认对齐方式通常(但不总是)是数据类型的大小。
过度对齐允许您将此对齐方式增加到大于默认值的程度。
至于你为什么要这样做:
这样做的一个原因是能够访问具有更大数据类型(具有更大对齐)的数据。
例如:
char buffer[16];
int *ptr = (int*)&buffer;
ptr[0] = 1;
ptr[1] = 2;
Run Code Online (Sandbox Code Playgroud)
默认情况下,缓冲区只会对齐到 1 个字节。但是,int
需要 4 字节对齐。如果buffer
未对齐到 4 个字节,则会出现未对齐异常。(AFAIK,ARM 不允许未对齐的内存访问...... x86/64 通常允许,但会降低性能)
__align()
会让你强制对齐更高以使其工作:
__align(4) char buffer[16];
Run Code Online (Sandbox Code Playgroud)
使用 SIMD 指令时会出现类似的情况。您将使用较大的 SIMD 数据类型访问较小的数据类型 - 这可能需要更大的对齐。
归档时间: |
|
查看次数: |
574 次 |
最近记录: |