【问题标题】:Multiple preincrement operations on a variable in C++(C ?)C ++(C?)中变量的多个预增量操作
【发布时间】:2011-04-11 01:08:47
【问题描述】:

为什么下面的代码会在 C++ 中编译?

int phew = 53;
++++++++++phew ;

相同的代码在 C 中失败,为什么?

【问题讨论】:

  • 添加 C++0x 标签只是为了好玩。 :)
  • 这类问题必须有一个标准问题我们可以参考。因此,所有问题(我们每年这个时候从新大学生那里得到的)都可以快速关闭并标记为阅读此内容。

标签: c++ c operators pre-increment operator-precedence


【解决方案1】:

注意:DR#637DR#222 这两个缺陷报告对于理解以下行为原理很重要。


为了解释,在 C++0x 中有value computationsside effects。例如,副作用是赋值,而值计算正在确定左值所指的内容或从左值中读取值。请注意,C++0x 不再有序列点,并且这些内容的措辞是“sequenced before”/“sequenced after”。并且据说

如果标量对象的副作用相对于同一标量对象的另一个副作用或使用同一标量对象的值的值计算是无序的,则行为未定义。

++v 等价于v += 1 等价于v = v + 1(除了 v 只计算一次)。这将产生++ (v = v + 1),我将其写为inc = inc + 1,其中inc 指的是v = v + 1 的左值结果。

在 C++0x 中,++ ++v 不是未定义的行为,因为对于 a = b,赋值顺序在 b 和 a 的值计算之后,但在赋值表达式的值计算之前。因此v = v + 1 中的赋值在inc 的值计算之前排序。而inc = inc + 1 中的赋值是在inc 的值计算之后排序的。最后,这两个分配将因此被排序,并且没有未定义的行为。

【讨论】:

  • 好答案。同样int a=4; ++a=5; 不会在 C++0x 中调用 UB,对吧?
  • @Johannes:我不明白为什么a = ++a 不会调用未定义的行为,但a = a++ 会。 “除非另有说明,单个运算符的操作数和单个表达式的子表达式的求值顺序以及副作用发生的顺序是未指定的”发生了什么?
  • @Daniel,第二个确实调用了未定义的行为,因为“a++”中对 a 的修改不是在之前排序,而是在 之后“a++”的值计算(自然,因为您希望它产生旧值)。因此,“a++”中的赋值和修改不是相对于彼此排序的。您引用的文本现在的措辞是“除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的评估是无序的。”
  • @Prasoon,对“a++”中的 a 的修改是在“a++”的值计算之后排序的。 “a + a++”中的两个 a 没有以任何方式排序,它们的值计算和副作用都没有。所以你有一个副作用(对 a 的修改),它相对于 a(第一个操作数)的值计算是无序的,所以你有 UB。
  • a = a++;涉及的步骤是 a) 'a' (lhs) 的左值的值计算 b) 'a' 的左值 (rhs) 的值计算,c) ++ 的副作用,d) 赋值的副作用。您的意思是在 C++0x 中,步骤 (d) 和 (c) 是无序的吗?
【解决方案2】:

这是因为在C++ 预增量运算符中返回一个lvalue,它要求它的操作数是一个lvalue

++++++++++phew ; 被解释为++(++(++(++(++phew))))

但是您的代码调用了Undefined Behaviour,因为您试图在两个sequence points 之间多次修改phew 的值。

C 中,预增量运算符返回一个rvalue,并要求其操作数是lvalue。所以你的代码不能在 C 模式下编译。

【讨论】:

  • @Prasoon:别再猜你了,我只是想知道你所说的; “您正试图在两个序列点之间多次修改 phew 的值”。您能否为标准的这一部分提供注释,以便我阅读更多相关信息?
  • @Merlyn Morgan-Graham:阅读 Steve Summit 的这篇文章:c-faq.com/expr/seqpoints.html
  • 明确一点,++++i 是为用户定义的类型定义良好的,对吧?
  • @FredOverflow:是的,因为函数调用引入了一个序列点。 :)
  • 这只是 C++03 中的 UB。它在 C++0x 中有效。
猜你喜欢
  • 2014-07-11
  • 2014-12-26
  • 1970-01-01
  • 2012-05-25
  • 2017-12-06
  • 1970-01-01
  • 2022-08-03
  • 1970-01-01
  • 2015-05-08
相关资源
最近更新 更多