以下语句在ANSI C中是否有效?它有效吗?

时间:2021-06-28 22:24:38

During my preparation to exam on ANSI C I have encountered the following question -

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

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

以下声明是否有效?如果没有,请进行必要的更改以使其有效。

The original statement is: test(i++,i++); it isn't valid because the behaviour is undefined according to K&R p202

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

The order of evaluation of arguments is unspecified

参数的评估顺序未指定

But can I change it to the following statement? test(i+=2, i+=3)?

但我可以将其更改为以下声明吗?测试(i + = 2,i + = 3)?

The problem that I haven't seen such record in K&R or any other source. But XCode compile it and run without any warning.

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

5 个解决方案

#1


Both are valid statements, i.e. legal C, and in both cases, the behavior is undefined.

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

#2


To add up to the existing answers, the key point is, the statement

要添加到现有答案,关键点是声明

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

invokes undefined behavior as much as

尽可能多地调用未定义的行为

test(i++,i++);

because, in both the cases, there is no sequence point scheduled for comma separator in function parameter list and hence, you end up modifying the value of the same variable twice in the scope of a single sequence point. This invokes undefined behaviour.

因为,在这两种情况下,在函数参数列表中没有为逗号分隔符安排序列点,因此,您最终会在单个序列点的范围内两次修改同一变量的值。这会调用未定义的行为。

#3


Statements are syntactically valid, both before and after the change. But still the problem will remain. If you are modifying an object in the argument, and the order of evaluation is unspecified.

在变更之前和之后,语句在语法上都是有效的。但问题仍然存在。如果要修改参数中的对象,则未指定评估顺序。

C99 Section 6.5.2.2 Paragraph 10

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.

函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点。

As per Section 3.4.4 Paragraph 1

根据第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.

使用未指明的值,或本国际标准提供两种或更多种可能性的其他行为,并且在任何情况下都不会对其进行任何进一步的要求。

On the other hand Section 3.4.3 Paragraph 1 tells

另一方面,第3.4.3节第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

使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不要求

In the case of the order or evaluation, it can be done in any order, depending on how the compiler generates the code, it might store in-memory in any order and also may pass the arguments through register. Once the code is generated, the binary will behave same everywhere. Therefore for one single binary the results will be identical every time, but depending on the decision of the compiler things can change.

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

The best idea is to avoid anything which seems to be incorrect or fancy. When in doubt, possibly it is an undefined, unspecified, implementation-defined behaviour. Therefore you can make the same thing unambiguous and deterministic as follows.

最好的想法是避免任何看似不正确或花哨的东西。如果有疑问,可能是未定义的,未指定的,实现定义的行为。因此,你可以使同样的事情明确和确定如下。

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

OR

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

Depending on what order you want.

取决于您想要的顺序。

#4


As others have already noted, the behaviour in both cases is undefined, even if the code is syntactically valid in both cases. I assume the question uses "valid" to mean "correct", as in a strictly conforming C program. To make the statement correct, you must first know/derive its intent.

正如其他人已经注意到的那样,两种情况下的行为都是未定义的,即使代码在语法上都有效。我认为这个问题使用“有效”来表示“正确”,就像严格符合C程序一样。要使语句正确,您必须首先知道/获得其意图。

That could in fact be impossible without some external source telling you exactly what that intent is, but let's assume for the sake of argument that the programmer wishes to invoke the function test with the parameters (i+1, i+2) (in order of appearance). It would be best to communicate this intent by simply:

如果没有一些外部来源告诉你这个意图究竟是什么,那实际上是不可能的,但是我们假设程序员希望用参数(i + 1,i + 2)来调用函数测试(按顺序)外观)。最好通过以下方式传达此意图:

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

avoiding any ill effects introduced by the unspecified order of evaluation of function arguments.

避免由函数参数的未指定的评估顺序引入的任何不良影响。

#5


This sentence is quite confusing: test(i++,i++); it isn't valid because the behaviour is undefined according to K&R p202 .

这句话很混乱:test(i ++,i ++);它无效,因为根据K&R p202,行为未定义。

The truth is this statement has always been invalid in C. From the original specification of C by Kernighan and Ritchie in their book The C programming language to the latest C11 Standard published a few years ago, including the older C99 Standard and the obsolete C89 standard also known as ANSI C. Just not for the reason stated.

事实上,这句话在C语言中一直是无效的。从Kernighan和Ritchie的C语言原始规范到他们的书“C语言编程语言”到几年前发布的最新C11标准,包括旧的C99标准和过时的C89标准也被称为ANSI C.只是没有说明的原因。

The order in which the aguments to the function test are evaluated is unspecified, but this is not the problem here: both expressions modify the same variable and there is no sequence point between function argument evaluation. So it does not matter how you achieve side effects in the expressions used for the arguments, you invoke undefined behaviour. The compiler may generate code, but the rocket may explode upon take-off.

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

#1


Both are valid statements, i.e. legal C, and in both cases, the behavior is undefined.

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

#2


To add up to the existing answers, the key point is, the statement

要添加到现有答案,关键点是声明

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

invokes undefined behavior as much as

尽可能多地调用未定义的行为

test(i++,i++);

because, in both the cases, there is no sequence point scheduled for comma separator in function parameter list and hence, you end up modifying the value of the same variable twice in the scope of a single sequence point. This invokes undefined behaviour.

因为,在这两种情况下,在函数参数列表中没有为逗号分隔符安排序列点,因此,您最终会在单个序列点的范围内两次修改同一变量的值。这会调用未定义的行为。

#3


Statements are syntactically valid, both before and after the change. But still the problem will remain. If you are modifying an object in the argument, and the order of evaluation is unspecified.

在变更之前和之后,语句在语法上都是有效的。但问题仍然存在。如果要修改参数中的对象,则未指定评估顺序。

C99 Section 6.5.2.2 Paragraph 10

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.

函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点。

As per Section 3.4.4 Paragraph 1

根据第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.

使用未指明的值,或本国际标准提供两种或更多种可能性的其他行为,并且在任何情况下都不会对其进行任何进一步的要求。

On the other hand Section 3.4.3 Paragraph 1 tells

另一方面,第3.4.3节第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

使用不可移植或错误的程序结构或错误数据时的行为,本国际标准不要求

In the case of the order or evaluation, it can be done in any order, depending on how the compiler generates the code, it might store in-memory in any order and also may pass the arguments through register. Once the code is generated, the binary will behave same everywhere. Therefore for one single binary the results will be identical every time, but depending on the decision of the compiler things can change.

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

The best idea is to avoid anything which seems to be incorrect or fancy. When in doubt, possibly it is an undefined, unspecified, implementation-defined behaviour. Therefore you can make the same thing unambiguous and deterministic as follows.

最好的想法是避免任何看似不正确或花哨的东西。如果有疑问,可能是未定义的,未指定的,实现定义的行为。因此,你可以使同样的事情明确和确定如下。

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

OR

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

Depending on what order you want.

取决于您想要的顺序。

#4


As others have already noted, the behaviour in both cases is undefined, even if the code is syntactically valid in both cases. I assume the question uses "valid" to mean "correct", as in a strictly conforming C program. To make the statement correct, you must first know/derive its intent.

正如其他人已经注意到的那样,两种情况下的行为都是未定义的,即使代码在语法上都有效。我认为这个问题使用“有效”来表示“正确”,就像严格符合C程序一样。要使语句正确,您必须首先知道/获得其意图。

That could in fact be impossible without some external source telling you exactly what that intent is, but let's assume for the sake of argument that the programmer wishes to invoke the function test with the parameters (i+1, i+2) (in order of appearance). It would be best to communicate this intent by simply:

如果没有一些外部来源告诉你这个意图究竟是什么,那实际上是不可能的,但是我们假设程序员希望用参数(i + 1,i + 2)来调用函数测试(按顺序)外观)。最好通过以下方式传达此意图:

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

avoiding any ill effects introduced by the unspecified order of evaluation of function arguments.

避免由函数参数的未指定的评估顺序引入的任何不良影响。

#5


This sentence is quite confusing: test(i++,i++); it isn't valid because the behaviour is undefined according to K&R p202 .

这句话很混乱:test(i ++,i ++);它无效,因为根据K&R p202,行为未定义。

The truth is this statement has always been invalid in C. From the original specification of C by Kernighan and Ritchie in their book The C programming language to the latest C11 Standard published a few years ago, including the older C99 Standard and the obsolete C89 standard also known as ANSI C. Just not for the reason stated.

事实上,这句话在C语言中一直是无效的。从Kernighan和Ritchie的C语言原始规范到他们的书“C语言编程语言”到几年前发布的最新C11标准,包括旧的C99标准和过时的C89标准也被称为ANSI C.只是没有说明的原因。

The order in which the aguments to the function test are evaluated is unspecified, but this is not the problem here: both expressions modify the same variable and there is no sequence point between function argument evaluation. So it does not matter how you achieve side effects in the expressions used for the arguments, you invoke undefined behaviour. The compiler may generate code, but the rocket may explode upon take-off.

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