为什么使用函数调用而不是变量地址来检测堆栈增长方向?
我读到了对检测堆栈增长检测问题的不同回答,我了解到,在现代架构中,堆栈可能会随机增长,可能会在堆外创建,等等。
然而,在这个经典的面试问题中,我想了解为什么人们使用函数调用而不是比较同一函数中的 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;
}
我还发现这篇文章试图优化我也不理解的解决方案: http://www.devx.com/tips/Tip/37412
PS:从对此主题和其他主题的不同回应来看,这个问题本身似乎是有缺陷/不相关的,作为一个面试问题,它可能除非有人研究答案,否则会再次强化错误的假设!
谢谢!
I read different responses to the question of detecting stack growth detection and I understand that, in modern architectures, stack might grow randomly, might be created off heap, and so on.
However, in this classic interview question, I want to understand why people use a function call rather than comparing 2 local variables in the same function. I think there must be some particular reason for doing this but, not being a C/low level developer [Java :)], I am simply guessing.
Here is the code I tried:
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;
}
I also found this article which tries to optimize the solution which I don't understand either: http://www.devx.com/tips/Tip/37412
P.S: From different responses to this and other threads, it seems like the question itself is flawed/irrelevant, as an interview question it probably re-enforces incorrect assumptions unless someone researches the answer !
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您无法完全控制编译器选择分配局部变量的顺序。但是,您可以合理地控制将调用的函数以及调用顺序。
You can't fully control the order the compiler chooses to allocate the local variables in. You can however reasonably control the functions that will be called, and in what order.
声明的变量放入堆栈的顺序是未定义的,但在函数调用的函数中,内部函数调用的参数必然晚于外部函数的参数入栈。
The order that declared variables will be placed on the stack is undefined, but in a function called by a function, the inner function call's arguments will necessarily be pushed on the stack later than the outer function's.
在单个堆栈帧中,编译器可以自由地按其认为合适的方式对局部变量进行排序,因此代码:
可能在
ji
代码>.只要编译生成正确的代码来访问变量,它就可以去任何地方。事实上,除非您使用取址运算符
&
(或者必须获取地址),否则变量可能永远不会位于堆栈上。它可以在调用期间存储在寄存器中。但是,堆栈帧本身的放置顺序受到限制,因为如果它们乱序,函数返回将无法正常工作(温和地说)。
当然,我应该提到,堆栈增长的方向仅在非常有限的情况下有用。绝大多数代码不应该关心它。如果您对不同的架构以及它们如何处理堆栈感兴趣,请参阅 这个答案。
Within a single stack frame, the compiler is free to order the local variables as it sees fit, so the code:
may have
i
before or afterj
. As long as the compile generates the correct code to access the variable, it can go anywhere.In fact, unless you use the address-of operator
&
(or otherwise have to get at the address), the variable may never even be on the stack. It may be stored in a register for the duration of the call.However, the order in which the stack frames themselves are put are restricted since, if they're out of order, function returns won't work that well (to put it mildly).
I should mention, of course, that the direction of stack growth is useful only in a very limited number of scenarios. The vast majority of code should never care about it. If you're interested in different architectures and how they handle stacks, see this answer.
编译器可能并且确实对堆栈帧中的变量进行重新排序:
在此处打印
(在 64 位 Linux 上使用 gcc 4.4.3)。 c2 已移至 c1 旁边。
Compilers may and do reorder variables in stack frames:
print
here (using gcc 4.4.3 on a 64 bits Linux). c2 has been moved next to c1.
问题是,当你这样做时:
你得到的结果与堆栈增长方向无关。了解堆栈增长方向的唯一方法是创建新的帧。编译器可以根据需要随意将
a
放在b
上方,或将a
放在b
下方。不同的编译器可能会给出不同的结果。但是,如果您调用另一个函数,则该函数的局部变量必须位于新的堆栈帧中,即沿着调用者变量的增长方向。
The problem is that when you do this:
The result you get has nothing to do with the stack growth direction. The only way you know which way the stack grows is by creating new frames. The compiler is free to put
a
aboveb
, ora
belowb
as it sees fit. Different compilers may give different results.However, if you call another function, that function's local variables have to be in a new stack frame, i.e., in the direction of growth from the caller's variables.