【问题标题】:Expression evaluation in CC 中的表达式求值
【发布时间】:2011-07-23 17:24:43
【问题描述】:

为什么下面这段C代码打印12 12 12

int main(int argc, char const *argv[]) {
  int a = 2, *f1, *f2;
  f1 = f2 = &a;
  *f2 += *f2 += a += 2.5;
  printf("%i %i %i\n", a, *f1, *f2);
  return 0;
}

【问题讨论】:

  • 真正的问题是你为什么要写这样的代码?
  • interview-question :P,也会添加该标签。可悲的是,他们问这样的问题让我很恼火。
  • 至少这个无用的 UB 问题的一周有一点变化......
  • 我希望他们提出这个问题的目的是让您回答代码具有未定义的行为,即使没有,它也会被令人反感地混淆并且永远不应该编写......
  • 我同意,但我无能为力,也没有名为“未定义行为”的选项

标签: c undefined-behavior expression-evaluation


【解决方案1】:
*f2 += *f2 += a += 2.5;

此行包含Undefined Behavior,因为您在同一个表达式中多次更改*f2(即a)的值,而没有插入序列点。 UB 意味着你的程序可能会打印“Hello World”,它可能会崩溃,它可能会打印12 12 12 或12 12 1029,或者它可能会开始吞噬你的大脑。不要依赖未定义的行为。

引用 C++ 标准(我知道问题被标记为 C,但我没有 C 标准,我知道 C 中也有同样的规则)

除非另有说明,否则单个运算符的操作数和单个子表达式的求值顺序 表达式和副作用发生的顺序是未指定的。53) 并且下一个序列点标量对象的存储值最多只能通过评估修改一次 的一种表达方式。此外,只能访问先验值以确定要存储的值。 对于完整的子表达式的每个允许排序,都应满足本段的要求。 表达;否则行为是未定义。

【讨论】:

  • 您能解释一下被否决的原因吗?
  • 我没有给你投反对票,但我真的会因为你对这篇文章的自大态度而投反对票。用“实际上是你的错,它的这个”来评论有效的答案应该得到自我打击。尤其是当你真的连问题都没有回答时,彼得回答了,你只是引用了一个标准并称之为“魔法”
  • @SomeoneRandom:我确实回答了这个问题。彼得刚刚猜到了。我希望有一天你会明白,语言是它的标准,仅此而已。在此期间,请随意投我反对票
  • 您的回答是“我不知道,它可能是随机的”,这根本不是真的,每次都会产生相同的结果。是的,语言是由它的标准定义的,但他没有对此提出任何问题,他想要解释为什么它会产生它所做的事情。因此,您没有回答问题。
  • @SomeoneRandom:“我不知道,它的随机性可能是任何东西”是正确答案。 “每次都会产生相同的结果”是不正确的。例如,违反我在回答中引用的规则的表达式的结果通常取决于优化级别。
【解决方案2】:

它为所有人打印出相同的值,因为您只指向一个 int 变量:a。

它打印出12,因为a + 2.5 = 4(a 是int),然后你将它添加到自身两次。


@Downvoters:为什么这么消极?我认为我的回答说明了 此编译器 在 此示例代码 上做了什么,这应该有助于 OP 理解行为。我同意Armen Tsirunyan 的答案是正确的(即应该打勾)并且behaviour is undefined according to the standard。但是标准已经实现了,我还没有看到一个编译器编译代码然后在运行时突然举手说Undefined behaviour!。

【讨论】:

  • 实际上是未定义的行为
  • 按照标准,是的。我只是说 this example 似乎在做什么。我同意 OP 需要了解这是未定义的行为。
【解决方案3】:

因为*f2 和*f1 指向a(整数)。

所以*f2 = &a = 2 和*f1 = &a = 2

此时您将2.5 的值添加到a(因为a 是一个整数,您将获得4)。

比你有的

a = 4
f2 = 4
f1 = 4

此时你做f2+f1+a = 12.

【讨论】:

  • 实际上是未定义的行为
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
相关资源
最近更新 更多