什么是“堆栈对齐"?

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

What is stack alignment? Why is it used? Can it be controlled by compiler settings?

此问题的详细信息取自尝试将 ffmpeg 库与 msvc 一起使用时所面临的问题,但是我真正感兴趣的是对堆栈对齐"的解释.

The details of this question are taken from a problem faced when trying to use ffmpeg libraries with msvc, however what I'm really interested in is an explanation of what is "stack alignment".

细节:

  • 当运行我的 msvc 编译程序链接到 avcodec 时,我得到以下错误:编译器没有对齐堆栈变量.Libavcodec 有被错误编译",然后在 avcodec.dll 中崩溃.
  • avcodec.dll 不是用 msvc 编译的,所以我看不到里面发生了什么.
  • 当运行 ffmpeg.exe 并使用相同的 avcodec.dll 时,一切正常.
  • ffmpeg.exe 不是用 msvc 编译的,它是用 gcc/mingw 编译的(与 avcodec.dll 相同)

谢谢,

推荐答案

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

Alignment of variables in memory (a short history).

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

In the past computers had an 8 bits databus. This means, that each clock cycle 8 bits of information could be processed. Which was fine then.

然后是 16 位计算机.由于向下兼容等问题,保留了8位字节,引入了16位字.每个字是 2 个字节.并且每个时钟周期可以处理 16 位信息.但这带来了一个小问题.

Then came 16 bit computers. Due to downward compatibility and other issues, the 8 bit byte was kept and the 16 bit word was introduced. Each word was 2 bytes. And each clock cycle 16 bits of information could be processed. But this posed a small problem.

让我们看一个内存映射:

Let's look at a memory map:

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

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

At each address there is a byte which can be accessed individually. But words can only be fetched at even addresses. So if we read a word at 0000, we read the bytes at 0000 and 0001. But if we want to read the word at position 0001, we need two read accesses. First 0000,0001 and then 0002,0003 and we only keep 0001,0002.

当然,这需要一些额外的时间,而这并没有受到重视.所以这就是他们发明对齐方式的原因.所以我们将字变量存储在字边界,字节变量存储在字节边界.

Of course this took some extra time and that was not appreciated. So that's why they invented alignment. So we store word variables at word boundaries and byte variables at byte boundaries.

例如,如果我们有一个包含字节字段 (B) 和字字段 (W) 的结构(以及一个非常幼稚的编译器),我们会得到以下结果:

For example, if we have a structure with a byte field (B) and a word field (W) (and a very naive compiler), we get the following:

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

这不好玩.但是在使用词对齐时我们发现:

Which is not fun. But when using word alignment we find:

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

这里为了访问速度牺牲了内存.

Here memory is sacrificed for access speed.

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

You can imagine that when using double word (4 bytes) or quad word (8 bytes) this is even more important. That's why with most modern compilers you can chose which alignment you are using while compiling the program.

相关文章