局部变量的安全性
Safety of Local Variable
以下函数是否安全,以返回指向局部变量的指针?
int * foo(void)
{
int a = 6;
int *p = &a;
return p;
}
如果没有,在什么条件下?如果是,编译器如何保证安全性?
尝试的测试案例:
int * foo(void)
{
int a = 6;
int *p = &a;
return p;
}
int * bar(void)
{
int b = 7;
int *p = &b;
return p;
}
int main()
{
int a = *foo();
int b = *bar();
printf("%d, %d, %dn", 1, 2, 3); //to mess up stack
printf("%d, %dn", a, b);
return 0;
}
它将成功打印"6,7"。然而,使用-O2,它会打印"0,0">
这样做的结果将是未定义的行为,这肯定是不安全的。
a
是函数(即automatic variable
)的局部变量,因此它被存储在堆栈中。当函数返回堆栈帧时,向上(或向下)移动,留下的内存可能会被下一个调用的函数覆盖,因此指针将指向内存中的相同方向,但可以是任何随机字节。
简而言之,它从来都不安全,因为分配给该变量的内存迟早会被重用。
它适用于您的示例,因为它们很简单,在返回指针和访问指针所指向的内存之间,堆栈上没有发生太多其他事情。
只有当您返回指针的内存被显式地分配了malloc或类似的东西时,它才是安全的。
此链接可以更好、更详细地解释这一点:http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/Mips/stack.html
这个函数永远都不安全。有时可能会意外地做你所期望的事情,但仅此而已。
稍微不那么简洁:返回指向局部变量的指针总是会引发未定义的行为。未定义的行为包括这次不会发生任何错误的可能性,而通常基于堆栈的C实现允许您在大多数情况下将指针解引用到堆栈顶部正上方的内存中。main
在函数返回后立即取消引用这些指针,这使得它更有可能"工作"(特别是,您的"弄乱堆栈"printf
不会影响任何事情,因为此时无效指针已经失效)。然而,将int a = *foo()
安排为segfault的实现将是一致的。
有趣的事实:C99的文本中没有出现"堆栈"一词。所有实现都需要支持递归函数调用,通常的方法是使用堆栈,但堆栈并不是唯一的方法。例如,Cheney在M.T.a.中,底层的C堆栈被重新用作垃圾收集器托儿所,所有的延续都是显式的——C实现和Scheme实现一样可以做到这一点。
- 使用的未初始化局部变量'Quick'
- 修复未初始化的局部变量错误
- 局部变量保留函数中的值
- 如何使用 C++ 中的继承函数访问派生类中的局部变量
- 将引用分配给局部变量,如果局部变量超出范围,它会超出范围吗?
- Gnuplot_i.hpp C++接口绘制局部变量而不是文件
- 如何在函数外部访问函数中局部变量的值?
- 赋予全局变量而不是局部变量优先级的函数 - (异常行为)
- C++中静态方法的局部变量范围
- 未初始化的局部变量错误甚至认为我初始化了它(C++)
- 离开范围后如何保护局部变量的值?
- 局部变量名称冲突
- C++ lambda:如何'freeze'局部变量的值?
- 我应该使我的局部变量常量还是可移动的
- 获取具有静态局部变量的绑定/推断捕获 lambda 的函数指针
- 全局和局部变量初始化与 constexpr 的差异背后的基本原理
- 返回对局部变量 - C++ 的引用
- 是否可以影响 C++ 中回调函数的局部变量?
- 警告 C4101 未引用的局部变量
- 局部变量的安全性