【问题标题】:C - function returning a pointer to a local variableC - 函数返回指向局部变量的指针
【发布时间】:2020-10-13 21:26:15
【问题描述】:

考虑下面的代码。

#include<stdio.h>
int *abc(); // this function returns a pointer of type int

int main()
{
    int *ptr;
    ptr = abc();
    printf("%d", *ptr);
    return 0;
}

int *abc()
{
    int i = 45500, *p;
    p = &i;
    return p;
}

输出:

45500

根据link,我知道这种行为是未定义的。但是为什么我每次运行程序时都会得到正确的值。

【问题讨论】:

  • 因为允许未定义的行为这样做。顺便说一句,我认为这个问题没有任何问题。赞成。
  • 因为你的程序很简单。尝试在对 abc()printf() 的调用之间插入对其他函数的调用
  • 那又怎样? “未定义”并不意味着“随机”...
  • 在调用abc() 之后和现有printf 之前添加这个:printf("Test string %d %d %d %d\n", 1, 2, 3, 4)。然后看看会发生什么:)
  • 调用 abc() 然后调用 def() 并在检查 p 指向什么之后......你可以将 i 设为静态,只要不存在重入问题...(例如修改*p 的线程...)

标签: c undefined-behavior


【解决方案1】:

每次调用abc 时,它都会将堆栈顶部的一个区域“标记”为写入所有局部变量的位置。它通过移动指示堆栈顶部位置的指针来做到这一点。该区域称为堆栈帧。当函数返回时,它表明它不想再使用该区域,方法是将堆栈指针移动到原来的位置。因此,如果您之后调用其他函数,它们将重用堆栈的该区域以用于自己的目的。但是在您的情况下,您还没有调用任何其他函数。所以堆栈的那个区域保持相同的状态。

以上所有内容都解释了您的代码的行为。并非所有 C 编译器都以这种方式实现函数,因此您不应依赖这种行为

【讨论】:

  • 这是非常实现特定的。
  • 是的,我只是为了满足他的好奇心而解释这种行为。
  • 以i8051的Keil C编译器为例:它通过在链接时构建调用树来分配数据段中的局部变量,因此堆栈仅用于传递控制
  • @Serge:它如何处理递归?
  • 规范符合现实。我和其他人讨论过这个问题。有时,无法为给定的芯片架构创建符合标准的编译器。这并不意味着几乎兼容的编译器并不比原始汇编器好。此外,这些编译器通常是 C90
【解决方案2】:

好吧,未定义的行为是未定义的。你永远不能依赖 UB(或调用UB的程序的输出)。

也许,只是也许在您的环境和您的代码中,为局部变量分配的内存位置不会被操作系统回收并且仍然可访问,但不能保证它在任何其他平台上都具有相同的行为。

【讨论】:

  • 什么是 UB ??请定义
  • @Cody UB -> 未定义的行为。
猜你喜欢
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 2016-10-25
  • 1970-01-01
相关资源
最近更新 更多