我的理解是,只要调用testStack
,就会创建一个新的堆栈帧,并且所有局部变量都将存在于该堆栈帧中。一旦堆栈帧被删除,那些局部变量也将消失。
在下面的程序中,我返回了testStack
中创建的一个局部变量的内存位置,我能够在main
方法中再次访问该变量值。
问题:
在testStack
局部变量x
是在堆栈上创建的,其值也在堆栈上。
如果不是int x;
我已经说过int* x;
string testStack();
int main(void){
string memAdd = testStack();
printf("memAdd = %i\n", memAdd);
printf("*memAdd = %i\n", *memAdd);
printf("*&memAdd = %i\n", *&memAdd);
*&memAdd = 11;
printf("*&memAdd = %i\n", *&memAdd);
}
string testStack(){
int x;
printf("%i\n", x);
printf("%i %p %p\n", x, x, &x);
*&x = 33;
printf("%i\n", x);
//free(x);
return &x;
}
O / P:
134513341
134513341 0x80482bd 0xbffd9eac
33
memAdd = -1073897812
*memAdd = 33 //From main method... Stack frame of testStack() should have been removed by now...
*&memAdd = -1073897812
*&memAdd = 11
答案 0 :(得分:2)
其他人或多或少地回答了你的问题。这里有一些更详细的信息:
1.“我的理解是,一旦调用了testStack,就会创建一个新的堆栈帧,并且所有局部变量都将存在于该堆栈帧中”
无法保证将创建堆栈帧。编译器可能决定传递寄存器中的所有参数,并可能将所有本地存储在寄存器中。这可能发生在有大量寄存器和本地人很少的功能的CPU上。
一个。就堆而言:标准术语是堆不是代码或堆栈(而不是为全局变量保留的空间),您可以通过malloc()从中分配。堆栈通常以与堆相反的方向生长,因此当您在堆栈上推送某些内容时,剩余的堆空间会更少。如果一个参数在寄存器中传递,并且locals也在寄存器中,那么该片段将使用更少的堆栈/堆空间..我们不需要存储这些变量。
湾int x vs int * x:x只是一个局部变量,我想不出任何情况,当它的类型会有所不同时(除了int的大小(以位为单位)与大小不同的例外情况一个不错的编译器可能适合这样的架构,也许是ARM的拇指模式?)。因此,如果编译器决定(可能是函数很小,频繁调用,可内联),本地将保存在寄存器中,那么就不会创建堆栈帧。
答案 1 :(得分:1)
在x86
平台上,通过增加esp
寄存器并从堆栈恢复ebp
寄存器来移除小屋框架。在下一个程序调用之前,不会触及堆栈内存,您可以访问它。但是其他平台可以以不同方式处理这些事情,因此从已删除的堆栈帧访问内存是未定义的行为。
修改强>
1)如果使用指针而会有什么不同吗?嗯,这取决于。如果您在堆上分配数据(使用例如new
运算符),然后从您的过程返回指针 - 这是完全有效的技术。否则它几乎一样。
2)它可能有潜在危险吗?嗯,你必须澄清我们实际上在这里说的那种危险。这是有效的编程方法吗?当然不是。这是UB。这是潜在的安全漏洞吗?是的,也许吧。您不能指望编译器可以保证堆栈帧内存清理,您必须使用特殊方法自行完成。