以下声明在 ANSI C 中有效吗?它是否有效?

Is following statement valid in ANSI C? Is it valid at all?

在准备 ANSI C 考试期间,我遇到了以下问题 -

Is following statement valid?
If not, please make required changes to make it valid.

原始陈述是:test(i++,i++);它无效,因为根据 K&R p202

,该行为未定义

The order of evaluation of arguments is unspecified

但是我可以改成下面的语句吗? test(i+=2, i+=3)?

我在K&R 或任何其他来源中都没有看到这样的记录的问题。但是 XCode 编译它并且 运行 没有任何警告。

两者都是有效的语句,即合法的 C,并且在这两种情况下,行为都是未定义的。

这句话非常令人困惑:test(i++,i++); 它无效,因为根据 K&R p202 未定义行为。

其实这个说法在C一直是无效的。从 Kernighan 和 Ritchie 在他们的书 The C programming language 中对 C 的原始规范到几年前发布的最新 C11 标准,包括较旧的 C99 标准和过时的 C89 标准也为人所知作为 ANSI C。只是不是出于所述原因。

函数 test 的参数求值顺序未指定,但这不是这里的问题:两个表达式都修改同一个变量,并且函数参数求值之间没有序列点。因此,无论您如何在用于参数的表达式中实现副作用,您都会调用未定义的行为。编译器可能会生成代码,但火箭可能会在起飞时爆炸。

把现有的答案加起来,重点是,语句

test(i+=2, i+=3)

调用未定义行为的次数与

一样多
test(i++,i++);

因为,在这两种情况下,都没有为逗号分隔符[=25=安排序列点 ] 在函数参数列表中,因此,您最终修改了 same 变量的值 twice in the scope[=25] =] 单个序列点。这会调用 undefined behaviour.

更改前后的语句在句法上都是有效的。但问题仍然存在。如果您正在修改参数中的对象,并且未指定求值顺序。

C99 第 6.5.2.2 节第 10 段

The order of evaluation of the function designator,the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

根据第 3.4.4 节第 1 段

unspecified behaviour

use of an unspecified value, or other behavior where this International Standard provides two or more possibilities and imposes no further requirements on which is chosen in any instance.

另一方面Section 3.4.3 Paragraph 1告诉

undefined behaviour

behavior,upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirement

在顺序或评估的情况下,它可以按任何顺序完成,具体取决于编译器如何生成代码,它可以按任何顺序存储在内存中,也可以通过寄存器传递参数。生成代码后,二进制文件在任何地方的行为都相同。因此,对于一个二进制文件,每次的结果都是相同的,但根据编译器的决定,事情可能会发生变化。

最好的办法是避免任何看起来不正确或花哨的事情。如果有疑问,它可能是未定义的、未指定的、实现定义的行为。因此,您可以像下面这样使同样的事情变得明确和确定。

test (i, i+1);
i += 2;

test (i+1, i);
i+= 2;

取决于你想要的顺序。

正如其他人已经指出的那样,两种情况下的行为都是未定义的,即使代码在这两种情况下都是语法有效。我假设这个问题使用 "valid" 来表示 "correct",就像在严格符合 C 程序中一样。要使陈述正确,您必须首先 know/derive 它的意图。

事实上,如果没有一些外部来源告诉您确切的意图是什么,这可能是不可能的,但是为了论证,我们假设程序员希望使用参数 [=12] 调用函数 test =](按出现顺序)。最好通过以下方式传达此意图:

test (i + 1, i + 2);
i += 2;

避免因未指定函数参数求值顺序而引入的任何不良影响。