为什么函数调用而不是变量地址用于检测堆栈增长方向?

cod*_*ver 8 c c++ stack low-level

我读到了检测堆栈增长检测问题的不同响应,我理解,在现代架构中,堆栈可能会随机增长,可能会在堆外创建,依此类推.

但是,在这个经典的访谈问题中,我想了解为什么人们使用函数调用而不是在同一函数中比较2个局部变量.我认为必须有一些特殊的理由这样做,但不是一个C /低级开发人员[Java :)],我只是在猜测.

这是我试过的代码:

void sub (int *a)  {
    int b;
    int c;
    printf ("a:%d\n", a);
    printf ("b:%d\n", &b);
    printf ("c:%d\n", &c);
    if (&b > a) {
        printf ("Stack grows up.\n");
    } else {
        printf ("Stack grows down.\n");
    }
}

int main (void) {
    int a;
    int b;
    sub (&a);
    printf ("\nHere we go again!!\n");
    if (&b > &a)  {
        printf ("Stack grows up.\n");
    } else  {
        printf ("Stack grows down.\n");
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我还发现这篇文章试图优化我不理解的解决方案:http://www.devx.com/tips/Tip/37412

PS:从对这个和其他线索的不同反应来看,似乎问题本身是有缺陷/不相关的,作为面试问题它可能会重新执行不正确的假设,除非有人研究答案!

谢谢!

Ign*_*ams 6

您无法完全控制编译器选择分配局部变量的顺序.但是,您可以合理地控制将要调用的函数以及按什么顺序控制.


Gru*_*rig 5

声明变量将放置在堆栈上的顺序是未定义的,但在函数调用的函数中,内部函数调用的参数必须晚于外部函数的推送.


pax*_*blo 4

单个堆栈帧中,编译器可以自由地按其认为合适的方式对局部变量进行排序,因此代码:

int i;
double j;
Run Code Online (Sandbox Code Playgroud)

可能有i之前或之后j。只要编译生成正确的代码来访问变量,它就可以去任何地方。

事实上,除非您使用取址运算符&(或者必须获取地址),否则该变量可能永远不会堆栈上。它可以在调用期间存储在寄存器中。

但是,堆栈帧本身的放置顺序受到限制,因为如果它们乱序,函数返回将无法正常工作(温和地说)。


当然,我应该提到,堆栈增长的方向仅在非常有限的情况下有用。绝大多数代码不应该关心它。如果您对不同的架构以及它们如何处理堆栈感兴趣,请参阅此答案