理解C语言中的栈帧

6
我正在试图理解C语言中的栈帧,所以我编写了一个简单的C代码来分析栈帧。
首先,fun1()返回一个本地变量的地址,该变量被初始化为10并赋值给ptr。虽然会出现警告,但这没关系......如果我现在打印*ptr的值,它会打印10,这也没问题......
接下来,fun2()返回一个未初始化的本地变量的地址。无论我是返回a还是b的地址,如果我尝试打印*ptr的值,它都会打印10,这就很奇怪了......
为了理解实际发生了什么,我使用了gdb。使用gdb,我逐步调试,当我到达fun2()中的"return &a"一行时,我尝试打印b的地址,print &b,但它打印了Can't take address of "b" which isn't an lvalue. 我不明白为什么当我尝试打印a的地址print &a, 它完全正常地打印,但为什么不能打印b的地址。 * 为什么b不是lvalue而a是?
# include <stdio.h>

int * fun1() {
    int a = 10; 
    return &a; 
}

int * fun2()
{
    int a;
    int b;
    return &a;           // return &b;
}

int main ()  
{
    int *ptr;
    ptr = fun1();
    ptr = fun2();
    printf ("*ptr = %d, fun2() called...\n", *ptr);
    return 0;
}

http://stackoverflow.com/a/18479996/1814023 - user1814023
1
你正在调用未定义的行为。不能保证结果有任何意义或符合堆栈布局的预期。标准夸张说法是程序可以让鼻子里飞出恶魔 - user2357112
2
你很幸运,打印*ptr显示为10;但这并不是保证的(你触发了未定义行为)。 但你真的应该展示所有的代码。在代码中,编译器可能会将b作为一个未使用的变量删除,因此它没有位置,因此无法取其地址。在代码中以某种方式使用b,然后你就可以打印它了。而且,请不要报告“类似于”;要准确,并报告调试器确切的消息。 - Jonathan Leffler
如果您正在寻找有关“堆栈帧”方面的文档,则这是与任何特定编程语言无关的ABI相关请求,您应该了解您的CPU/架构/操作系统/实现所采用/提供的ABI。 如果您的问题是理解C语言的工作原理,则重点是完全不同的主题。 - user2485710
2个回答

3

编译器正在优化fun2中的某些代码。

如果你返回&a,它将优化掉int b;。如果你返回&b,它将优化掉int a;。如果你添加一些虚假计算,你会发现返回值的地址是不同的。

int * fun2()
{
    int a;
    int b;
    int* p = &a;
    p = &b;
    return p;
}

main函数修改为打印fun1fun2的返回值。

int main ()  
{
    int *ptr;
    ptr = fun1();
    printf ("ptr = %p, fun1() called...\n", ptr);
    ptr = fun2();
    printf ("ptr = %p, fun2() called...\n", ptr);
    printf ("*ptr = %d, fun2() called...\n", *ptr);
    return 0;
}

当我运行这段代码时,我会得到以下示例输出:
ptr = 0x7ffff98c70ec,调用fun1()...
ptr = 0x7ffff98c70e4,调用fun2()...
*ptr = 32749,调用fun2()...

是的,如果我初始化b,它会返回一个垃圾值,但是如果我使用-O0级别的优化编译,结果应该也是一样的。但是当我使用-O0级别的优化编译时,结果再次相同,即10。 - Adarsh

0

当我返回b的地址时,它对我来说编译得很好。但是你不应该返回局部变量的地址。查看此链接


是的,那是真的,但我的目标不是从这段代码中实现任何东西,而是理解如何在一个函数中使用堆栈变量的地址并在另一个函数中重新使用它...感谢您的帮助... - Adarsh

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