这个问题是关于c和c++中对于参数,变量在内存中地址分配的问题。对于以下代码
int main (int argc, char *argv[]) { int a; int b; a = 1; b = 2; return 0; }
我的理解是,main函数是通过初始函数调用,main函数实际和其他函数一样。
在初始函数调用main函数后,会先将返回地址压入堆栈,接着将参数压入堆栈。面对函数中定义的局部变量,将会按照定义顺序分配堆栈内存空间。而堆栈是从高地址向低地址生长的,所以我认为&a > &b。
然而,在gdb调试过程中,我发现&b > &a。请问我的理解在哪里错了?
大家讲道理2017-04-17 11:06:28
局部變量的空間不是一個一個壓入棧中的,而是一次性分配好的,所以理解為變量依次入棧是錯誤的。C語言也沒有規定局部變量在內存中的位置,隻是常常實現為先定義的變量在高地址、後定義的變量在低地址。不過局部變量在棧上的位置沒有絕對的關係,甚至不一定會出現在棧上。比如你的代碼做這樣的調整,改成下麵這樣:
#include<stdio.h> int main() { int a = 1; int b = 2; printf( "a = %d, b = %d\n", a, b ); printf( "&a = %08x, &b = %08x\n", &a, &b ); return 0; }
這個時候你會發現a變量確實分配在高地址,而b變量分配在低地址。如果你把你的程序加上-O2參數優化一下,那麼a和b這兩個變量因為沒有被真正的使用,而被編譯器優化掉,你直接p &a會得不到任何的值。
怪我咯2017-04-17 11:06:28
“棧”這個數據結構本身並沒有規定其生長的方向,具體實現中向高地址或者低地址生長都無妨。但是對於操作係統而言,棧的生長方向一般是取決於處理器對PUSH/POP操作的實現。對於x86來說,PUSH以後SP/ESP的值是減小,因此它是向低地址生長的,樣例代碼:
#include <stdio.h> void stack_growth(char *function_parameter) { char local; if (&local > function_parameter) printf("up\n"); else printf("down\n"); printf("%p %p\n", &local, function_parameter); } int main() { char c = 'c'; stack_growth(&c); return 0; }
而聲明一個變量,無非是告訴編譯器,在棧上給它準備一塊空間。因此你所提及的情況,實際上與棧無直接關係:a先聲明的話,就一定會先在棧上為它分配空間嗎?舉個最簡單的栗子,如果a根本沒被用到,編譯器完全可以不為它分配空間。所以這個最終還是取決於編譯器的實現。
補充一段WIKI吧:
Some processors families, such as the x86, have special instructions for manipulating the stack of the currently executing thread. Other processor families, including PowerPC and MIPS, do not have explicit stack support, but instead rely on convention and delegate stack management to the operating system's Application Binary Interface (ABI).