为什么在C++中(C++)*(C++)未定义的行为?
的问题是“序列点”:
http://en.wikipedia.org/wiki/Sequence_point
在命令式编程的序列点定义在它被保证在 计算机程序的执行的任何一点,所有的边以前 影响评估已经完成,并且没有任何方面的后续评估影响尚未执行。
当单个表达式中多次修改相同变量 时,序列点也会发挥作用。一个经常引用的例子是 C表达式i = i ++,它明显地指定了它以前的 值并且增量i。 i的最终值不明确,因为 取决于表达式评估的顺序,所以增量可能发生在赋值之前,之后或交错。特定语言的定义可能会指定其中一个可能的行为,或者简单地说行为是未定义的。在C和C++中, 评估这样的表达式会产生未定义的行为。[1]
碰巧,我在MSVC(Windows)和gcc(Linux)上得到了完全相同的答案 - “9”。我也收到了警告我是否与海湾合作委员会(“C”)或g ++(C++)编译:
$ g++ -o tmp -Wall -pedantic tmp.cpp
tmp.cpp: In function "main(int, char**)":
tmp.cpp:7: warning: operation on "c" may be undefined
$ ./tmp
c=9...
而在'tcc'和'clang'我得到'12'。 :) – Jack 2012-04-29 04:50:42
的C时的参数使许多事情没有意义,他们几乎任凭谁实现了自由裁量权语言(即编写一个编译器)。在这些未定义的事情中,这些表达的各个部分的评估顺序是。
例如,是先乘后计算乘积++
es,还是先计算一个++
再乘以,那么其他++
?
评估顺序不是未定义的行为 - 这是未指定的行为。不同之处在于编译器无法做任何想要的事情 - 它仍然需要正确评估表达式。它不需要以任何特定顺序执行评估(除了某些操作会强制执行命令)。另一方面,表达式'i + = ++ i'是未定义的 - 这里*没有*正确的行为,编译器可以自由地执行任何想要的操作。 – 2012-04-29 09:16:16
未定义的行为意味着任何东西都可能发生。
输出为9
,但使用不同的编译器或不同的编译器开关,它也可能是12
,0
或2147483647
。
它可能会格式化您的硬盘驱动器! – orlp 2012-04-29 04:52:07
根据如何编写编译器,使用什么标志来编译,月相的相位等,答案可能是9,16,20,或者它可能产生nasal demons。总是尽量避免混淆代码和未定义的行为。查看如何避免这种情况的顺序点。想着序列点,为什么你的榜样的
好吧,我会咬人的。我期望9,12或16,那么你如何得到20? – 2012-04-29 08:55:24
@Mr。李斯特:这是未定义行为的本质。 – 2012-04-29 22:02:54
一种方式既有unspecified behavior
和undefined behavior
是通过考虑首先介绍了临时变量的实现:
这样的实现可能会处理后增量如下:
tmp_1=c; // read 'c'
tmp_2 = tmp_1 + 1; // calculate the incremented value
c = tmp_2; // write to 'c'
tmp_1; // the result of the expression
原表达(c++)*(c++)
有两个序列:
lhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
lhs_1; // the resulting value of the expression
rhs_1=c; // read 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
rhs_1; // the resulting value of the expression
的顺序可以是:
lhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
rhs_1=c; // read 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
lhs_1 * rhs_1 // (3 * 4) new value of 'c' is 5
或者:
lhs_1=c; // read 'c'
rhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
lhs_1 * rhs_1 // (3 * 3) new value of 'c' is 4
或者:
rhs_1=c; // read 'c'
rhs_2 = rhs_1 + 1; // calculate the incremented value
c = rhs_2; // write to 'c'
lhs_1=c; // read 'c'
lhs_2 = lhs_1 + 1; // calculate the incremented value
c = lhs_2; // write to 'c'
lhs_1 * rhs_1 // (4 * 3) new value of 'c' is 5
....等。
unspecified behavior
是它可以先评估lhs或rhs。 undefined behavior
是我们正在读写c
,没有中间顺序点。
那么,这是c + +不是c – 2012-04-29 04:19:24
相同的结果,相同的问题,无论是C或C++ – paulsm4 2012-04-29 04:29:29
@ paulsm4不是。在C中,这是非常特定的行为:你会得到一个编译器错误。 – 2012-04-29 08:53:45