我 = ++i + ++i; 在 C++
有人能向我解释为什么这段代码打印 14 吗? 刚才有一个同学问我,我没能弄清楚。
int i = 5;
i = ++i + ++i;
cout<<i;
Can someone explain to me why this code prints 14? I was just asked by another student and couldn't figure it out.
int i = 5;
i = ++i + ++i;
cout<<i;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
C++ 中未定义副作用的顺序。 此外,在单个表达式中修改变量两次没有定义的行为(请参阅 C++ 标准,§5.0.4,物理页 87 / 逻辑页 73)。
解决方案:在复杂的表达式中不要使用副作用,在简单的表达式中不要使用多个副作用。 启用编译器可以向您提供的所有警告也没有什么坏处:将
-Wall
(gcc) 或/Wall /W4
(Visual C++) 添加到命令行会产生适当的警告:显然,代码编译为:
The order of side effects is undefined in C++. Additionally, modifying a variable twice in a single expression has no defined behavior (See the C++ standard, §5.0.4, physical page 87 / logical page 73).
Solution: Don't use side effects in complex expression, don't use more than one in simple ones. And it does not hurt to enable all the warnings the compiler can give you: Adding
-Wall
(gcc) or/Wall /W4
(Visual C++) to the command line yields a fitting warning:Obviously, the code compiles to:
这是未定义的行为,结果将根据您使用的编译器而有所不同。 例如,请参阅C++ FAQ Lite。
That's undefined behaviour, the result will vary depending on the compiler you use. See, for example, C++ FAQ Lite.
在一些答案/评论中,讨论了“未定义行为”的含义以及这是否会使程序无效。 因此,我发布了这个相当长的答案,详细说明了标准的内容以及一些注释。 我希望它不会太无聊...
该标准引用的部分来自当前的 C++ 标准 (ISO/IEC 14882:2003)。 C 标准中也有类似的措辞。
根据 C++ 标准,在一组序列点内多次修改某个值会导致未定义的行为(第 5 节第 4 段):
请注意,由于逗号运算符是序列点,因此定义了第二个示例“
i = 7, i++, i++;
”。以下是 C++ 标准所说的“未定义行为”的含义:
换句话说,编译器可以自由地做任何它想做的事情,包括
第二项涵盖大多数编译器具有的语言扩展,但当然没有在标准中定义。
所以我想严格来说,表现出未定义行为的东西并不是“非法的”,但根据我的经验,每当 C/C++ 程序中出现表现出“未定义行为”的东西(除非它是扩展)时,这就是一个错误。 我认为称这样的构造为非法并不令人困惑、误导或误导。
另外,我认为尝试解释编译器为达到值 14 所做的事情并不是特别有帮助,因为这没有抓住要点。 编译器几乎可以做任何事情; 事实上,当编译器使用不同的优化选项运行时,它可能会得到不同的结果(或者可能产生崩溃的代码 - 谁知道呢?)。
对于那些想要一些额外的参考资料或求助于权威的人,这里有一些提示:
Steve Summit(comp.lang.c 常见问题的维护者)1995 年关于这个主题的很长的答案:
以下是 Bjarne Stroustrup 对此事的看法:
脚注:C++ 标准仅使用一次“非法”一词 - 在描述 C++ 和 C++ 之间的差异时关于在类型声明中使用
static
或extern
的标准 C。In some of the answers/comments there has been a discussion about the meaning of 'undefined behavior' and whether that makes the program invalid. So I'm posting this rather long answer detailing exactly what the standard says with some notes. I hope it's not too boring...
The quoted bits of the standard come from the current C++ standard (ISO/IEC 14882:2003). There's similar wording in the C standard.
According to the C++ standard, modifying a value more than once within a set of sequence points results in undefined behavior (section 5 Paragraph 4):
Note that the second example, "
i = 7, i++, i++;
" is defined since the comma operator is a sequence point.Here's what the C++ standard says 'undefined behavior' means:
In other words, the compiler is free to do whatever it wants, including
The second item covers language extensions which most compilers have, but of course are not defined in the standard.
So I guess that strictly speaking something that exhibits undefined behavior is not 'illegal', but in my experience whenever there's been something in a C/C++ program that exhibits 'undefined behavior' (unless it's an extension) - it's a bug. I think that calling such a construct illegal is not confusing, misleading, or misguided.
Also, I think trying to explain what the compiler is doing to reach the value 14 is not particularly helpful, as that misses the point. The compiler could be doing almost anything; in fact, it's likely that the compiler may reach a different result when it's run using differing optimization options (or may produce code that crashes - who knows?).
For those who want some additional references or an appeal to authority, here are some pointers:
Steve Summit's (maintainer of the comp.lang.c Frequently Asked Questions) long, long answer on this topic from 1995:
Here's what Bjarne Stroustrup has to say on the matter:
Footnote: the C++ standard uses the word 'illegal' exactly once - when describing a difference between C++ and Standard C regarding the use of
static
orextern
with type declarations.简单...编译器在执行求和之前评估两个增量,而不缓存中间结果。 这意味着当您添加 i 两次时,它现在的值为 7。
如果这样做,
您将看到预期的 13。
Simple... you compiler is evaluating BOTH increments before performing the sum, without caching the intermediate results. This means that when you add i twice, it now has the value of 7.
If you do
you'll see 13 as expected.
我认为从语法树的角度看问题,问题的答案就变得更加清晰:
i
|
=
|
+
|
一元表达式 - 一元表达式
一元表达式:一元运算符表达式
在我们的例子中,表达式归结为变量 i。
现在发生的情况是两个一元表达式都修改相同的操作数,因此代码在计算一元表达式时执行两次 ++i,然后再将两个一元表达式的结果相加。
所以代码的作用确实是
++i;
++i;
i = i + i;
对于 i = 5,这意味着
我=我+1; //i <- 6
我=我+1; //i <- 7
我=我+我; //i <- 14
I think that when looking at the problem from the sight of the syntax tree, the answer to the problem becomes clearer:
i
|
=
|
+
|
unary expression - unary expression
unary expression: unary operator expression
In our case expression boils down to the variable i.
Now what happens is that both unary expression modify the same operand, so the code does two times ++i when evaluating the unary expressions before adding the results of both unary expressions.
So what the code does is indeed
++i;
++i;
i = i + i;
For i = 5 that means
i = i + 1; //i <- 6
i = i + 1; //i <- 7
i = i + i; //i <- 14
更好的问题是,它总是
14
吗?很可能它会是
14
,因为它稍微更有意义。A better question would be, is it always going to be
14
?In all likelihood it will probably be
14
, because it makes slightly more sense.因为前缀增量有优先级:
Because the prefix increment has precedence: