我有以下程序.我想知道为什么它在下面的64位机器上输出-4?我的哪些假设出了问题?
[Linux ubuntu 3.2.0-23-generic#36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux]
在上面的机器和gcc编译器中,默认情况下应该先推送b和第二个.堆栈向下增长.所以b应该有更高的地址和更低的地址.所以结果应该是积极的.但我得到了-4.任何人都能解释一下吗?
参数是在堆栈帧中占用2个字节的两个字符.但是我看到差异为4,正如我所期望的那样1.即使有人说这是因为对齐,那么我想知道一个带有2个字符的结构未对齐4个字节.
Run Code Online (Sandbox Code Playgroud)#include <stdio.h> #include <stdlib.h> #include <unistd.h> void CompareAddress(char a, char b) { printf("Differs=%ld\n", (intptr_t )&b - (intptr_t )&a); } int main() { CompareAddress('a','b'); return 0; } /* Differs= -4 */
回答这些问题(关于特定平台上特定编译器的行为)的最佳方法是查看汇编程序.您可以gcc通过传递-S标志来转储其汇编程序(并且-fverbose-asm标志也很好).运行
gcc -S -fverbose-asm file.c
Run Code Online (Sandbox Code Playgroud)
给出了一个file.s看起来有点像(我已经删除了所有不相关的位,并在括号中的位是我的笔记):
CompareAddress:
# ("allocate" memory on the stack for local variables)
subq $16, %rsp
# (put a and b onto the stack)
movl %edi, %edx # a, tmp62
movl %esi, %eax # b, tmp63
movb %dl, -4(%rbp) # tmp62, a
movb %al, -8(%rbp) # tmp63, b
# (get their addresses)
leaq -8(%rbp), %rdx #, b.0
leaq -4(%rbp), %rax #, a.1
subq %rax, %rdx # a.1, D.4597 (&b - &a)
# (set up the parameters for the printf call)
movl $.LC0, %eax #, D.4598
movq %rdx, %rsi # D.4597,
movq %rax, %rdi # D.4598,
movl $0, %eax #,
call printf #
main:
# (put 'a' and 'b' into the registers for the function call)
movl $98, %esi #,
movl $97, %edi #,
call CompareAddress
Run Code Online (Sandbox Code Playgroud)
(这个问题很好地解释了什么[re]bp和[re]sp.)
差异为负的原因是堆栈向下增长:即如果您将两个东西推入堆栈,那么您首先推送的那个将具有更大的地址,并且a之前被推送b.
原因-4不是-1编译器决定将参数与4字节边界对齐是"更好",可能是因为32位/ 64位CPU在处理4个字节时比处理单个字节更好.
(另外,查看汇编程序会显示具有的效果-mpreferred-stack-boundary:它实质上意味着堆栈上的内存以不同大小的块分配.)