直接使用地址运算符返回局部变量的地址与使用指针变量返回该地址的区别

3

我知道从函数返回局部变量的地址是错误的做法。但当我尝试展示这个事实时,遇到了一个问题。请看以下程序:

int *test()
{
    int x = 12;
    int *p = &x;
    return p;
}

int main()
{
    int *p = test();
    printf("%p",p);
    return 0;
}

它如预期一样打印出类似于0061fed0的地址。但是,如果我直接使用&返回x的地址,即如果将test函数更改为以下内容:

int *test()
{
    int x = 12;
    return &x;
}

那么输出结果就变成了00000000。请您解释一下这里到底发生了什么?我正在使用在Windows 10上捆绑的Code:Blocks 17.12 IDE附带的gcc编译器。

关于重复问题: 建议的重复问题: C - GCC生成错误的指令来返回本地堆栈地址 解释了直接使用地址运算符的行为,但未解决使用指针变量返回局部变量地址的情况,在StoryTeller's的回答中进行了解释:“当指向的对象(或刚超过)达到其生命周期的末尾时,指针的值变得不确定”。


2
未定义行为是指没有定义的行为。编译器没有义务生成任何有意义的代码。猜测它为什么生成了某种无意义的代码并不特别有趣。 - Lundin
1
当指针所指向的对象(或紧邻其后)到达其生命周期的末尾时,指针的值变得不确定。我之前并不知道这一点。这就是为什么我提出了这个问题。 - Imran Rana
1个回答

4

严格来说,从C语言规范的角度来看,这是一个有效的结果。

6.2.4 对象的存储期 (我加重了语气)

2 对象的生命周期是程序执行过程中保证为其保留存储空间的部分。对象存在,具有固定的地址,并在其生命周期内保留其最后存储的值。如果在对象的生命周期外引用对象,则行为是未定义的。当指向对象(或刚刚超出对象)的指针到达其生命周期的末尾时,指针的值变得不确定。

因此,无论哪种情况下函数返回的值都是不确定的。您无法预测它将是什么,甚至不能以有意义的方式使用它。使用不确定值的程序具有未定义的行为,任何事情都可能发生。

所以,你的编译器会在你直接返回本地地址时返回null。根据C语言本身,这是一个有效值,因为该对象很快就会死亡。但它有一个好处,即在现代托管实现中很可能会早期崩溃程序,从而使你能够修复错误。

当指针所指向的对象(或刚好超过其寿命)到达生命周期的末尾时,指针的值变得不确定。- 这就是我在寻找的内容。谢谢。 - Imran Rana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接