【问题标题】:Why does value of automatic object persist after lifetime ends? [closed]为什么自动对象的价值在生命周期结束后仍然存在? [关闭]
【发布时间】:2014-01-28 14:12:15
【问题描述】:

我正在准备面试。

我的 c 程序是:

void foo(void)
{
    int a;
    printf("%d\n",a);
}

void bar(void)
{
    int a=42;
}

void main(void)
{
    bar();
    foo();
}

我得到的输出是:42

但是怎么做呢?我认为这将是一些垃圾值。

执行栈或激活帧的概念是如何应用的?

请解释

谢谢

【问题讨论】:

  • 42 是一个完全合理的垃圾值
  • 由于“无法再复制的问题或简单的印刷错误”而关闭的投票是不合时宜的。这个问题也不是。它可以通过关闭优化在大多数 C 实现中重现,这显然不是印刷错误。
  • 我不是反对者,但我完全理解为什么有人不喜欢您的帖子:(1)问题标题包含的信息不多,它谈论的是您的个人问题,而​​不是技术问题您遇到 (2) 任何好书或其他资源都应该告诉您,您不应该打印未使用具有足够警告级别的值 (3) 初始化的变量,现在任何体面的编译器都应该哭泣。
  • @JensGustedt:(2)无关紧要。 OP没有询问这是否是好的做法或为什么。他们问了一个不同的问题,为什么当它不在 C 标准规定的行为范围内时会观察到这种行为。事实上,这样做的原因确实存在,而且原因在于计算机编程领域。

标签: c output


【解决方案1】:

a 未在函数 foo 中初始化。打印未初始化的变量会调用未定义的行为
在这种情况下,您可能会得到任何结果,无论是预期的还是意外的结果。在我的编译器上,输出是

 4203214  

结果可能会因编译器而异,即使是同一编译器的不同版本也会给您带来不同的结果。
但是您获得42 的可能原因之一是因为自动变量通常分配在执行堆栈上。在调用bar 之后,42 被放入执行堆栈。该值保持在堆栈中不受干扰。当调用foo 时,它可能读取a 的堆栈空间并打印42
尝试优化您的代码(使用-o 编译),您可能会得到a 的一些不同值。

【讨论】:

  • 这个答案是不正确的,因为“未定义的行为”绝不是任何行为的原因;这是缺乏原因。 OP 观察到的行为发生的原因确实存在。这些原因在于通常如何实现函数调用和自动变量。
  • @EricPostpischil;为什么我得到不同的结果?
  • @hacks:您得到了不同的结果,因为您的 C 实现的行为与 OP 的 C 实现不同。但这种差异并不是由 C 标准未定义行为这一事实引起的。它是由两个 C 实现的实现者做出的决定引起的。 OP 观察到“42”的输出这一事实无疑是由于 bar 将 42 放置在堆栈上,保持原状,并且在 foo 使用它时发现在那里。 C 标准并没有造成这种情况。堆栈的使用确实如此。
  • @EricPostpischil;但是a 未初始化。这不是调用 UB 吗?
  • @hacks:“调用 UB”这个短语是错误的。假设您是父母,您十几岁的孩子下午出去玩,而您没有告诉他们去哪里。你的孩子去看电影。那是未定义的行为:您没有指定他们必须去看电影。你让他们去看电影了吗?您是否调用了他们未定义的行为?如果有人问你的孩子为什么去看电影,你会说他们去看电影是因为你没有具体说明他们必须去哪里吗?这没有任何意义。你没有调用任何东西。它的发生有其他原因。
【解决方案2】:

bar() 的调用将值42 放入堆栈。调用foo() 时它仍然存在。

bar()foo() 的堆栈帧可能相同,或者至少足够相似,因此foo() 中的a 保持42 的值。

当然,这不能保证,并且是未定义的行为。但是,对于调试代码,通常需要一些理解,而不是像通常那样简单地忽略这些问题。

如果你提高优化级别(至少在 gcc 中),你看到的行为会改变。

【讨论】:

  • 最后一句应该说“可能会改变”而不是“会改变”。
【解决方案3】:

当您从main() 调用bar() 时,它会设置a = 42,它位于堆栈中,距离main() 执行位置低一个int。当您从main() 调用foo() 时,它会打印a 的值,在此范围内,该值也在堆栈中,距离main() 执行位置低一个int。

通过首先调用bar(),你已经在堆栈上设置了数据,并且由于foo()bar()具有相同的调用帧,bar()afoo()a以相同的内存地址结束。

不过,正如其他答案所指出的,这是未定义的行为。在这种情况下,该值会保留在堆栈中并最终位于同一位置。

【讨论】:

    猜你喜欢
    • 2022-01-01
    • 2020-12-25
    • 2013-08-22
    • 2019-01-06
    • 2017-02-17
    • 1970-01-01
    • 2011-06-16
    • 2012-04-25
    相关资源
    最近更新 更多