【问题标题】:Understanding Stack Frames in C了解 C 中的堆栈帧
【发布时间】:2014-06-10 16:14:22
【问题描述】:

我试图理解 C 中的堆栈帧,所以我编写了一个简单的 C 代码来分析堆栈帧。

  • 首先 fun1() 返回一个局部变量的地址,该变量初始化为 10 到 ptr,这会导致警告,但没关系...如果我现在打印 *ptr 的值,它会打印 10 ,就算这样也好……

  • Next fun2() 返回一个甚至没有初始化的局部变量的地址,如果我现在尝试打印 *ptr 的值,无论我返回的是 a 还是 b 的地址,它都会打印 10 ...

  • 为了了解这里实际发生的情况,我使用了 gdb。 使用 gdb,我开始逐步调试,当我到达 fun2() 中的“return &a”行时,我尝试打印 b 的地址,print &b 但它打印 无法获取不是左值的“b”地址。

我不明白当我尝试打印 a 的地址时,print &a 它打印得非常好,那么为什么不打印 b 的地址。 * 为什么 b 不是左值,而 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;
}

【问题讨论】:

  • 您正在调用未定义的行为。无法保证结果会有意义或符合您对堆栈布局的期望。标准的夸张是允许程序让demons飞出你的鼻子。
  • 你很幸运,打印 *ptr 打印 10;当然不能保证这样做(您正在调用未定义的行为)。但是您确实应该显示所有代码。在代码中,编译器可能将b 作为未使用的变量丢弃,因此它没有位置,因此您无法获取它的地址。在代码中使用b,不知何故,您将能够打印它。请不要报告“类似”;准确,并准确报告调试器所说的内容。
  • 如果您要获取有关“堆栈框架”的文档,那么这是一个与 ABI 相关的请求,与任何编程语言都没有任何关系,您应该记录自己采用/提供的 ABI你的 CPU/架构/操作系统/实现。如果您的问题是理解 C 的工作原理,那么重点是完全不同的主题。

标签: c gcc gdb memory-layout


【解决方案1】:

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

如果您返回&amp;a,它正在优化int b;。如果您返回&amp;b,它正在优化int a;。如果添加一些虚拟计算,您会看到返回值的地址会有所不同。

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

更改main 以打印fun1 和fun2 的返回值。

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
【解决方案2】:

将地址返回给 b 时,它对我来说编译得很好。但是您不应该返回局部变量的地址。 Check out this link.

【讨论】:

  • 是的,但我的目的不是从这段代码中完成任何事情,而是了解如何在一个函数中使用堆栈变量的地址可以在另一个函数中重用......谢谢帮助...
猜你喜欢
  • 1970-01-01
  • 2017-12-05
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 2013-10-07
  • 2015-08-17
  • 2021-12-26
  • 2016-01-12
相关资源
最近更新 更多