2011-11-18 86 views
1

请参阅下面的代码示例。 函数中的函数fun_ret_loc_ptr()返回一个警告:“函数返回局部变量的地址”。另一方面,函数fun_ret_loc_var()中的语句return a不这样做。为什么gcc在返回指向局部变量的指针时抛出警告,而不是在返回局部变量时抛出警告?

#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 (&i);)审阅到,这是对应于起作用fun_ret_loc_ptr()堆栈帧的一部分的存储器位置。一旦这个函数返回,栈帧(激活记录)就会被销毁。同样的东西应该适用于函数fun_ret_loc_var()中的变量'a'(return a;)。即使它被返回,当它在main中被使用时,对应于'a'的内存也会死掉。

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

回答

5

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

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

现在,如果程序好像做你所期望的,那纯属巧合。这就是所谓的Undefined Behaviour。事实上,结果可能是任何事情(从你的汽车吹起来到在未来三周内仔细做午饭吧,这只是undefined

2

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

+0

如果函数返回值,主函数如何知道返回值返回哪个位置? – Abhijeet

+1

@Abhijeet:在返回期间,函数将其返回值推送到堆栈。然后调用者函数从堆栈中检索(例如:弹出)它。 – jweyrich

+2

@jweyrich复制返回值的位置取决于正在使用的调用约定。它可能会被传回寄存器或跨越多个寄存器。 – James

1

您可以通过按值或引用传递参数来进行类比。

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

0

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