【问题标题】:Why does gcc throw a warning when returning a pointer to a local variable and not when returning a local variable?为什么 gcc 在返回指向局部变量的指针而不是返回局部变量时会抛出警告?
【发布时间】:2012-01-01 07:53:34
【问题描述】:

请参阅下面的代码示例。 函数fun_ret_loc_ptr() 中的语句return (&i) 返回警告:“函数返回局部变量的地址”。另一方面,函数fun_ret_loc_var() 中的语句return a 没有这样做。

#include <stdio.h>
int* fun_ret_loc_ptr()
{
   int i = 10;
   return (&i);
}

int fun_ret_loc_var()
{
   int a = 20;
   return a;
}

int main()
{
   printf("val frm local ptr = %d\n", *fun_ret_loc_ptr());
   printf("val frm local var = %d\n", fun_ret_loc_var());
}

我了解到,在第一个函数中,返回的地址 (return (&amp;i);) 引用了一个内存位置,该内存位置是对应于函数 fun_ret_loc_ptr() 的堆栈帧的一部分。一旦此函数返回堆栈帧(激活记录)将被销毁。同样的事情应该适用于函数fun_ret_loc_var() 中的变量'a' (return a;)。即使返回了,但在main中使用时,'a'对应的内存也会死掉。

从“return”语句的功能来看,为什么会出现这种差异?

【问题讨论】:

    标签: c gcc compiler-construction operating-system


    【解决方案1】:

    按值返回变量会复制它,因此从函数返回后使用它是安全的。

    返回对局部变量的引用(或指针)是不安全的(因为从函数返回后引用/指针不再有效)。

    现在,如果程序似乎按照您的预期进行,那纯属巧合。这称为 Undefined Behaviour。事实上,结果可能是任何事情(从你的汽车爆炸到为接下来的三周精心准备午餐。只是未定义

    【讨论】:

      【解决方案2】:

      您在帖子末尾很好地解释了这个解释。您唯一的“错误”是说变量 a 在函数调用结束时“死亡”。实际上它确实死了,但返回的是 a 的副本,而不是函数堆栈中的 a 。因此,访问该函数的返回值是没有问题的。

      【讨论】:

      • 如果按值返回,主函数如何知道返回值返回到哪个位置?
      • @Abhijeet:在返回期间,函数将其返回值推入堆栈。调用者函数然后从堆栈中检索(例如:弹出)它。
      • @jweyrich 返回值的复制位置取决于使用的调用约定。它可以在一个寄存器中传回,也可以跨多个寄存器传回。
      • @James:说得好! :) 在其他架构(如 MIPS)的实现中也是如此。
      • 事实上,过去 20 年来我使用的每个平台都对整数、指针和浮点数等原始类型使用寄存器返回,而不是堆栈返回。
      【解决方案3】:

      您可以考虑通过值或引用传递参数的类比。

      在这里,您通过引用或按值返回值。如果按值返回值,则该值在调用者中可用。如果通过引用返回值,则将值的引用返回给调用者。要访问该值,调用者必须取消引用,但该引用不再指向任何有效值。

      【讨论】:

        【解决方案4】:

        函数不返回变量;它们返回。该值是否来自局部变量无关紧要;即使没有,它也来自一个“局部表达式”(我的术语),它的生命周期甚至比局部变量的生命周期还要短。返回指向本地(假​​设它是自动的,而不是静态的)变量的指针的问题是指针的 是无效的,并且在函数返回后对它的任何使用都会导致未定义的行为。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-14
          • 2016-10-25
          • 1970-01-01
          • 2013-10-03
          • 1970-01-01
          • 2020-10-13
          相关资源
          最近更新 更多