在函数外存取局部变量的一个比喻

在函数外存取局部变量的一个比喻

在StackOverflow上一这样一个关于C/C++的问题,问问题的人给了一个代码如下:

int * foo()
{
    int a = 5;
    return &a;
}

int main()
{
    int* p = foo();
    cout << *p;
    *p = 8;
    cout << *p;
}

你可以编译并运行这个代码(编译时会有一个Warning),结果是:5 8。看上去你可以存取一个函数内的局部变量。但这和我们理解的不一样——函数内的变量在函数退出时就被释放了,不应该在外部还可以被引用。当然,对于C/C++熟悉的人都知道其实并不是真正的释放,你依然还可以通过内存地址去进行操作,这是C/C++的内存管理的不安全性——指针可以用来乱指。

这个问题的解答是比较简单的,但是这个问题有一个答案中的比喻非常精彩。这个比喻是这样的——

你在某个酒店订了一个房,你入住的时候,你放了一本书在这个酒店的抽屉里,但是你走的时候,你忘了这本书。而且,你还没有把这个房间的钥匙还回去。于是,你在未来某个时候,偷偷地回来,打开这个房间的门,你看到了你的书还在里间。当然,还还可以放回别的书。因为,这个酒店管理不会在你走的时候把你留下的书清走,而且,这个酒店的管理的安保措施不是那么严格,因为他信任每一个客人都会遵守管理条例。

在这种情况下,如果你幸运的话,书还会在那里,也可能你的书已经没了。也有可能当你回去的时候,有一个人在那里正在撕你的书,或者酒店把那个抽屉都挪走并变成衣柜,或是整个酒店正在被拆除以改成了一个足球场,而你偷偷摸摸进到施工现场的时候被炸死。

真是很精彩的比喻。这就是C/C++的不安全的地方,也正是Linus说的,C++是一门恐怖的语言是因为有很多不合格的程序员在使用它。就像你看到小孩子玩火一样的恐怖。

关于这个事,还有一个比较经典的示例如下—— 函数a的初始化会影响函数b的数组。注意函数a中的 volatile 关键字。

#include <iostream>
using namespace std; 
void a()
{
    volatile int array[10];
    for (int i = 0; i < 10; i++)
        array[i] = i;
}

void b()
{
    int array[10];
    for (int i = 0; i < 10; i++)
        cout << array[i];
}

int main()
{
    a();
    b();
}

真是可爱的C/C++。

(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)

好烂啊有点差凑合看看还不错很精彩 (16 人打了分,平均分: 4.19 )
Loading...

在函数外存取局部变量的一个比喻》的相关评论

  1. 主要是进入函数时候根据函数中局部变量大小抬高栈顶分配空间,退出时候降低栈顶释放栈空间,虽然栈顶变了,但是栈里的内容并没有消除,所以a函数中关闭优化后分配了栈控件并初始化了数组的值,然后函数退出,降低栈顶。b函数进入之后抬高栈顶,之前a函数里初始化的值又回来了。弱弱的问一句:对吧?

    1. 是的,这主要由CPU的工作方式决定,汇编的push,pop操作会不会清空重置POP操作之前的内容属于CPU指令设计范畴,编译器作者对此毫无办法.

  2. 一门语言或技术从诞生到完善势必要经历一个过程,那么,使用它们的程序员也需要静下心来好好的打磨自己能力。

  3. 大神啊,我发现一个更奇怪的问题:
    在Visual Studio 2010下,如果去掉volatile,那么
    Debug情况下,函数b的输出是函数a中array[10]的内容;
    Release情况下,函数b的输出就是从0到9了;

    另外,如果不去掉volatile,那么:
    Debug情况下,函数b的输出是函数a中array[10]的内容;
    Release情况下,函数b的输出既不是是函数a中array[10]的内容,也不是从0到9;一堆很奇怪的数。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注