return 如何作用于函数局部变量?

How does return work for a function local variable?

我对局部变量的 return 重新分级感到困惑:变量、它的地址和使用指针的返回地址。

第一个:

#include <stdio.h>

int returner(void);

int main(void)
{
    printf("The value I got is = %d\n", returner());
    return 0;
}

int returner(void)
{
    int a = 10;
    return a;
}

输出:

The value I got is = 10

返回了局部变量,尽管它应该在函数之后超出范围 returns,这是如何工作的?

第二个:

#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

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

输出:

Test.c: In function 'returner':
Test.c:15:12: warning: function returns address of local variable [-Wreturn-local-addr]
   15 |     return &a;

为什么没有返回地址,虽然在第一个示例中返回了值?

第三个:

#include <stdio.h>

int *returner(void);

int main(void)
{
    int *pointer = returner();
    printf("The value I got is = %d\n", *pointer);
    return 0;
}

int *returner(void)
{
    int a = 10;
    int *ptr = &a;
    return ptr;
}

输出:

The value I got is = 10

现在,这个方法如何返回局部变量的地址并打印出它的正确值,尽管变量应该超出范围/在函数之后被销毁returns?

请解释三种情况下的方法是如何工作的。

  • 首先输出:(没有范围)是return编辑的。
  • 第二个输出:您正在尝试 return 超出范围的地址。
  • 第三个输出:虽然您尝试做与之前相同的事情,但编译器没有检测到问题。然而,被 returned 的指针同样有问题。
int returner(void)
{
    int a = 10;
    return a;
}

上面的函数return是一个int的值,就return而言,相当于写了return 10;

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

以上是他们所谓的“未定义行为”的示例 - 有时它可能有效,但并不可靠。 returned 的地址指的是函数调用堆栈上的一个位置,用于为函数局部变量提供存储。在 returner return 秒后不再保留该内存用于保存 int a,尽管它可能没有被重用,并且可能在该地址处仍然具有值 10,因为一段时间后,无法保证。

第三个例子与第二个例子没有太大区别。行为可能与第二个不同,因为堆栈分配不同,但两者都不应期望持续工作或可移植。

从函数返回的是 avalue,就像传递给函数的是 value它的参数。

您唯一需要担心超出范围的时间是当您返回指向具有自动存储持续时间的局部函数变量的指针时,即:

int *badFunction ()
{
   int ret[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
   return ret;
}

在这种情况下,返回的值是指向数组 ret 的指针,但是,由于 retbadFunction 退出时超出范围,返回的指针显然无效.解决方法是使用具有 static 存储持续时间的变量或堆。

在您的情况下,使用普通的旧 int,您无需担心范围。

在 C 中,return 按值计算。

第一个代码return是a的值,也就是10,没关系,只是局部变量a.

的拷贝而已

第二个代码return是指向a的指针的值,也就是它的地址。恰好在函数超出范围后该地址将无效,并且存储在该地址中的局部变量的生命周期结束。编译器聪明足以检测到这一点并警告您。

第三个代码不同,有一个来自另一个指针的地址分配,编译器不会进一步检查分配的地址是否有效,额外的间接层会使编译器关闭.

输出仍然是 10 但这是偶然的,它是 undefined behavior, and as such, that is one of the possible outcomes. There is no standardized behavior for this kind of construct and to demonstrate it I tweaked things a bit. As you can see here https://godbolt.org/z/eKerdM,启用了优化 -O3

使用 clang 程序输出一些随机值:

The value I got is = -1313555320

并且没有产生任何警告。

gcc 进一步验证并检测到有问题的分配:

<source>: In function 'returner':
<source>:16:12: warning: function returns address of local variable 
[-Wreturn-local-addr]
  16 |     return ptr;
     |            ^~~
<source>:14:9: note: declared here
  14 |     int a = 10;
     |         ^

程序输出0:

The value I got is = 0

在这两种情况下,值不再 正确 ,并且 clang 的行为不同于 gcc