当前位置:  开发笔记 > 编程语言 > 正文

什么是"堆栈对齐"?

如何解决《什么是"堆栈对齐"?》经验,为你挑选了3个好方法。

什么是堆栈对齐?为什么用它?可以通过编译器设置来控制吗?

这个问题的细节来自于尝试将ffmpeg库与msvc一起使用时遇到的问题,但我真正感兴趣的是对"堆栈对齐"的解释.

细节:

当runnig我的msvc编译程序链接到avcodec我得到以下错误:"编译器没有对齐堆栈变量.Libavcodec已被错误编译",随后avcodec.dll崩溃.

avcodec.dll没有用msvc编译,所以我无法看到里面发生了什么.

运行ffmpeg.exe并使用相同的avcodec.dll时一切正常.

ffmpeg.exe没有用msvc编译,它符合gcc/mingw(与avcodec.dll相同)

谢谢,



1> Toon Krijthe..:

内存中变量的对齐(历史较短).

在过去,计算机具有8位数据总线.这意味着,每个时钟周期可以处理8位信息.那很好.

然后是16位电脑.由于向下兼容性和其他问题,保留了8位字节并引入了16位字.每个单词是2个字节.并且每个时钟周期可以处理16位信息.但这提出了一个小问题.

我们来看一个内存映射:

+----+
|0000| 
|0001|
+----+
|0002|
|0003|
+----+
|0004|
|0005|
+----+
| .. |

在每个地址都有一个可以单独访问的字节.但是单词只能在偶数地址获取.因此,如果我们在0000读取一个字,我们读取0000和0001处的字节.但是如果我们想要读取位置0001处的字,我们需要两次读访问.首先是0000,0001然后是0002,0003,我们只保留0001,0002.

当然,这需要一些额外的时间,这是不受欢迎的.所以这就是他们发明对齐的原因.因此,我们将字变量存储在字边界,将字节变量存储在字节边界.

例如,如果我们有一个带字节字段(B)和字段字段(W)(以及一个非常天真的编译器)的结构,我们得到以下结果:

+----+
|0000| B
|0001| W
+----+
|0002| W
|0003|
+----+

哪个不好玩.但是当使用单词对齐时,我们发现:

+----+
|0000| B
|0001| -
+----+
|0002| W
|0003| W
+----+

为了访问速度,牺牲了内存.

你可以想象,当使用双字(4字节)或四字(8字节)时,这更为重要.这就是为什么对于大多数现代编译器,您可以在编译程序时选择使用哪种对齐方式.


堆栈对齐的精彩描述!

2> Shaun Boucka..:

IIRC,堆栈对齐是指变量在堆栈上"对齐"到特定数量的字节.因此,如果使用16位堆栈对齐,则堆栈上的每个变量将从一个字节开始,该字节是函数中当前堆栈指针的2个字节的倍数.

这意味着如果使用<2字节的变量,例如char(1字节),则它与下一个变量之间将有8位未使用的"填充".这允许基于变量位置的假设进行某些优化.

在调用函数时,将参数传递给下一个函数的一种方法是将它们放在堆栈上(而不是将它们直接放入寄存器中).这里是否使用对齐很重要,因为调用函数将变量放在堆栈上,由调用函数使用偏移读取.如果调用函数对齐变量,并且被调用函数期望它们不对齐,则被调用函数将无法找到它们.

似乎msvc编译的代码不同意变量对齐.尝试编译并关闭所有优化.



3> snemarch..:

某些CPU体系结构需要特定的各种数据类型对齐,如果您不遵守此规则,则会抛出异常.在标准模式下,x86对基本数据类型不要求这样做,但可能会受到性能损失(请访问www.agner.org了解低级优化提示).

但是,SSE指令集(通常用于高性能)音频/视频处理具有严格的对齐要求,如果您尝试在未对齐的数据上使用它,则会抛出异常(除非您在某些处理器上使用更慢的未对齐版本) ).

你的问题是,可能是一个编译器预计呼叫者保持对齐堆栈,而其他预期的被调用,以在必要时将纸叠.

编辑:至于为什么发生异常,DLL中的例程可能想要在一些临时堆栈数据上使用SSE指令,并且因为两个不同的编译器不同意调用约定而失败.


保持对齐堆栈,而其他预期
,以在必要时将纸叠.
推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有