正确答案是:代码产生未定义的行为。
行为未定义的原因是两个表达式 ++x 和 x + 1 正在修改 x 并读取 x 出于不相关(与修改)的原因,并且这两个操作没有被序列点分隔.这会导致 C(和 C++)中的未定义行为。在 C 语言标准的 6.5/2 中给出了要求。
请注意,这种情况下的未定义行为与 printf 函数仅被赋予一个格式说明符和两个实际参数这一事实完全无关。给printf 提供比格式字符串中的格式说明符更多的参数在C 中是完全合法的。同样,问题的根源在于违反了C 语言的表达式求值要求。
另外请注意,本次讨论的一些参与者未能掌握未定义行为的概念,并坚持将其与未指定行为的概念混为一谈。为了更好地说明差异,让我们考虑以下简单示例
int inc_x(int *x) { return ++*x; }
int x_plus_1(int x) { return x + 1; }
int x = 1;
printf("%d", inc_x(&x), x_plus_1(x));
上面的代码和原来的代码是“等价的”,只是涉及到我们x的操作被包装到了函数中。在这个最新的例子中会发生什么?
此代码中没有未定义的行为。但由于printf 参数的评估顺序是未指定,因此此代码会产生未指定行为,即printf 可能会被称为printf("%d", 2, 2) 或作为printf("%d", 2, 3)。在这两种情况下,输出确实是2。但是,此变体的重要区别在于,对 x 的所有访问都被包装到每个函数开头和结尾的序列点中,因此此变体不会产生未定义的行为。
这正是其他一些发帖者试图强加于原始示例的原因。但这是不可能的。原始示例产生 undefined 行为,这是一个完全不同的野兽。他们显然试图坚持在实践中未定义的行为总是等同于未指定的行为。这是一个完全虚假的说法,仅表明制造它的人缺乏专业知识。原始代码产生未定义的行为,句号。
为了继续这个例子,让我们将之前的代码示例修改为
printf("%d %d", inc_x(&x), x_plus_1(x));
代码的输出通常会变得不可预测。它可以打印2 2,也可以打印2 3。但是请注意,即使行为是不可预测的,它仍然不会产生 未定义的行为。行为是未指定,而不是未定义。未指定的行为仅限于两种可能性:2 2 或 2 3。未定义的行为不限于任何事情。它可以格式化你的硬盘驱动器而不是打印一些东西。感受不同。