helloworld Asked:2020-02-19 21:59:36 +0000 UTC2020-02-19 21:59:36 +0000 UTC 2020-02-19 21:59:36 +0000 UTC 调用 printf 时的副作用(C 中参数的数量可变) 772 有这段代码: int i = 5; printf("%d %d %d", i++, i++, i++); 结论:7 6 5 为什么会出现这个结论?他们说它与可变数量的参数有关。 c 2 个回答 Voted Best Answer Harry 2020-02-19T22:05:44Z2020-02-19T22:05:44Z 一个非常简单的解释——由于标准没有说明函数参数的求值顺序,编译器会按照它认为合适的方式进行。所以你得到7 6 5,你可以得到5 6 7,或者说6 5 7......你得到所谓的未定义行为。 解释更精确,但也更复杂——阅读关于序列点的文献……例如,这里或这里。 AnT stands with Russia 2020-02-20T01:33:13Z2020-02-20T01:33:13Z 首先,问题与函数参数的可变数量无关printf。 其次,您的示例中的行为未定义(未定义的行为),因为影响变量的多个副作用i(将值i增加一个)没有以任何方式相对于彼此排序。 请注意,这种现象不能用函数参数求值顺序的不确定性来解释。这种解释是一种流行且相当普遍的误解。事实上,正是顺序的不确定性本身与本例中未定义行为的发生无关。如果“在手指上”表达,那么更重要的作用是独立表达式-参数的计算不是彼此孤立的,并且可以以任何方式相互“交织”。 例如,在这段代码中 int foo(int *p) { return (*p)++; } int i = 5; printf("%d %d %d", foo(&i), foo(&i), foo(&i)); 参数的评估顺序也没有指定,但是(!)这里没有未定义的行为。根本没有指定行为。通俗地说,其原因恰恰是两个独立调用中函数体的执行不能“交织”——它们是相对于彼此排序的,即使在这种情况下不知道如何。 请注意这个微妙之处:在您的示例中,副作用根本没有排序,但在我的示例中,它们以未指定的方式排序。这些是不同的东西。在您的情况下,行为未定义,在我的示例中,行为未指定。 在我的示例中,您可以获得 and 5 6 7、 and7 6 5等。行为未指定,但仅限于一组明确定义的可能行为。你的代码绝对什么都可能发生,大到编译器拒绝编译你的代码,大到教科书式的“格式化硬盘”,甚至教科书式的“鼻魔”崩溃。
一个非常简单的解释——由于标准没有说明函数参数的求值顺序,编译器会按照它认为合适的方式进行。所以你得到
7 6 5,你可以得到5 6 7,或者说6 5 7......你得到所谓的未定义行为。解释更精确,但也更复杂——阅读关于序列点的文献……例如,这里或这里。
首先,问题与函数参数的可变数量无关
printf。其次,您的示例中的行为未定义(未定义的行为),因为影响变量的多个副作用
i(将值i增加一个)没有以任何方式相对于彼此排序。请注意,这种现象不能用函数参数求值顺序的不确定性来解释。这种解释是一种流行且相当普遍的误解。事实上,正是顺序的不确定性本身与本例中未定义行为的发生无关。如果“在手指上”表达,那么更重要的作用是独立表达式-参数的计算不是彼此孤立的,并且可以以任何方式相互“交织”。
例如,在这段代码中
参数的评估顺序也没有指定,但是(!)这里没有未定义的行为。根本没有指定行为。通俗地说,其原因恰恰是两个独立调用中函数体的执行不能“交织”——它们是相对于彼此排序的,即使在这种情况下不知道如何。
请注意这个微妙之处:在您的示例中,副作用根本没有排序,但在我的示例中,它们以未指定的方式排序。这些是不同的东西。在您的情况下,行为未定义,在我的示例中,行为未指定。
在我的示例中,您可以获得 and
5 6 7、 and7 6 5等。行为未指定,但仅限于一组明确定义的可能行为。你的代码绝对什么都可能发生,大到编译器拒绝编译你的代码,大到教科书式的“格式化硬盘”,甚至教科书式的“鼻魔”崩溃。