堆栈上的局部变量分配顺序堆栈、变量、局部、顺序

2023-09-07 02:47:45 作者:悠然见幽蓝

看看这两个函数:

void function1() {
    int x;
    int y;
    int z;
    int *ret;
}

void function2() {
    char buffer1[4];
    char buffer2[4];
    char buffer3[4];
    int *ret;
}

如果我在 gdb 中的 function1() 处中断,并打印变量的地址,我会得到:

If I break at function1() in gdb, and print the addresses of the variables, I get this:

(gdb) p &x  
$1 = (int *) 0xbffff380
(gdb) p &y
$2 = (int *) 0xbffff384
(gdb) p &z
$3 = (int *) 0xbffff388
(gdb) p &ret
$4 = (int **) 0xbffff38c

如果我在 function2() 做同样的事情,我会得到:

If I do the same thing at function2(), I get this:

(gdb) p &buffer1
$1 = (char (*)[4]) 0xbffff388
(gdb) p &buffer2
$2 = (char (*)[4]) 0xbffff384
(gdb) p &buffer3
$3 = (char (*)[4]) 0xbffff380
(gdb) p &ret
$4 = (int **) 0xbffff38c

您会注意到,在这两个函数中,ret 存储在最靠近堆栈顶部的位置.在 function1() 中,其后是 zy,最后是 x.在 function2() 中,ret 后面是 buffer1,然后是 buffer2buffer3.为什么存储顺序会改变?我们在两种情况下都使用了相同数量的内存(4 字节 ints 与 4 字节 char 数组),所以这不会是填充问题.这种重新排序可能有什么原因,此外,是否可以通过查看 C 代码提前确定局部变量的排序方式?

You'll notice that in both functions, ret is stored closest to the top of the stack. In function1(), it is followed by z, y, and finally x. In function2(), ret is followed by buffer1, then buffer2 and buffer3. Why is the storage order changed? We're using the same amount of memory in both cases (4 byte ints vs 4 byte char arrays), so it can't be an issue of padding. What reasons could there be for this reordering, and furthermore, is it possible by looking at the C code to determine ahead of time how the local variables will be ordered?

现在我知道 C 的 ANSI 规范没有说明局部变量的存储顺序,并且允许编译器选择自己的顺序,但我想编译器有关于它如何存储的规则会处理这个问题,并解释为什么这些规则是这样的.

Now I'm aware that the ANSI spec for C says nothing about the order that local variables are stored in and that the compiler is allowed to chose its own order, but I would imagine that the compiler has rules as to how it takes care of this, and explanations as to why those rules were made to be as they are.

作为参考,我在 Mac OS 10.5.7 上使用 GCC 4.0.1

For reference I'm using GCC 4.0.1 on Mac OS 10.5.7

推荐答案

我不知道 为什么 GCC 以它的方式组织它的堆栈(虽然我猜你可以打开它的源代码或 this paper 并找出),但我可以告诉你如何保证特定堆栈变量的顺序,如果出于某种原因,你需要.只需将它们放在一个结构中:

I've no idea why GCC organizes its stack the way it does (though I guess you could crack open its source or this paper and find out), but I can tell you how to guarantee the order of specific stack variables if for some reason you need to. Simply put them in a struct:

void function1() {
    struct {
        int x;
        int y;
        int z;
        int *ret;
    } locals;
}

如果我没记错的话,规范保证 &ret >&z>&y>&x.我把我的 K&R 留在了工作中,所以我不能引用章节和诗句.

If my memory serves me correctly, spec guarantees that &ret > &z > &y > &x. I left my K&R at work so I can't quote chapter and verse though.