为什么以下代码会产生此输出:
代码段:
int a=10;
printf("%d%d%d",++a,a++,++a);
输出:
131113
如何评估参数?这取决于编译器吗?我用gcc编译器。谁能告诉我我的编译器如何评估它?如果编译器从右到左计算函数的参数,那么此代码的输出将如下:
121111
答案 0 :(得分:2)
那是未定义的行为。在sequence point中多次修改变量是未定义行为。
来自维基:
序列点定义计算机程序执行中的任何点 保证以前的所有副作用 评估将会进行,没有副作用 后来的评估工作尚未完成。
请阅读:Operator Precedence vs Order of Evaluation
如需全面了解,请阅读:Undefined Behavior and Sequence Points
你可以这样做:
int a=10;
int b = (++a,a++,++a);
因为逗号(,)是这里的运算符而不只是参数之间的分隔符,如printf
的情况。
答案 1 :(得分:1)
这实际上是unspecified behavior和undefined behavior的组合。
未指定,因为在此行中未指定函数参数的评估顺序:
printf("%d%d%d",++a,a++,++a);
^ ^ ^ ^
1 2 3 4
我们不知道将对1
到4
的哪个顺序函数进行评估,如果这是一个循环,在后续执行中,顺序可能会有所不同。这在C99草案标准部分6.5.2.2
函数调用段 10 中有所说明(强调我的):
评估函数指示符的顺序,实际参数,和 实际参数中的子表达式未指定,但有一个序列点 在实际通话之前。
这本身意味着程序的输出不可靠但我们还有未定义的行为,因为上面的代码在sequence point内多次修改a
。这部分由6.5
表达式段落 2 表示(强调我的):
在上一个和下一个序列点之间,对象应具有其存储值 通过表达式的评估最多修改一次。 72)此外,先前的值应该是只读的,以确定要存储的值。 73)
未定义的行为表示运行此程序可能会导致任何事情,包括它似乎正常工作,该术语在3.4.3
部分中定义并包含以下 note ,它解释了未定义行为的可能结果:
可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的文档方式执行,终止翻译或执行(发布诊断信息)。
除此之外,即使您可以获得可靠的结果,这样的代码也难以阅读,并且在复杂的项目中维持是一场噩梦。如果有其他更简单的方法来编写满足其他要求的代码,例如性能等......那么这就是你应该采取的方法。