l4m*_*4m2 24 c undefined-behavior
int f() {
static int i=0;
return ++i;
}
int g() {
return f() + f();
}
Run Code Online (Sandbox Code Playgroud)
是否g()返回3或者是结果undefined?
Joh*_*ode 18
章和节:
6.5.2.2函数调用
...
10在评估函数指示符和实际参数之后但在实际调用之前有一个序列点.调用函数(包括其他函数调用)中的每个评估(在执行被调用函数的主体之前或之后没有特别排序)对于被调用函数的执行是不确定地排序的.94)
94)换句话说,函数执行不会相互"交错"
Upshot是因为++i它是函数调用的一部分而在每个之间存在一个序列点.因此,这种行为是明确定义的.
它是否真的符合您的意图是另一回事.请注意,在某些时候,您冒着签名溢出的风险,这是未定义的.正如其他人所指出的那样,f() - f()可能无法给出您期望的结果(在这种情况下,不能保证从左到右的评估).
250*_*501 15
+运算符的两个操作数的评估未被排序1.
在实际函数调用2之前有一个序列点.这个序列点足以分离静态变量i的修改,使整个表达式不确定地排序,并且函数的顺序调用未指定3.
因此行为保持定义,并且对函数g的第一次调用将总是产生3,因为函数调用的未指定顺序不会影响结果.
定义了包含未指定行为的程序4.
(所有引用来自:ISO/IEC 9899:201x)
1(6.5表达式3)
除非后面指出,否则子表达的副作用和值计算未被排序.
2(6.5.2.2函数调用10)
在评估函数指示符和实际参数之后但在实际调用之前有一个序列点.
3 (5.1.2.3程序执行3)
当A在B之前或之后进行测序时,评估A和B是不确定的,但未指定哪一个.
4(4.一致性3)
在所有其他方面正确的程序,对正确数据进行操作,包含未指明的行为,应为正确的程序,并按照5.1.2.3的规定行事.
das*_*ght 11
没有理由将其定义为未定义,因为+操作是可交换的,并且因为有两个++操作的序列点要排序.
C标准在完整表达式之后以及在函数调用中输入函数之前具有序列点.因此,结果++将完全排序.而且,由于+是可交换的,所以调用的顺序f()不会改变结果.
请注意,相同的逻辑不适用于
return f() - f();
Run Code Online (Sandbox Code Playgroud)
因为-是不是交换.上面表达式的结果是未指定的,即符合标准的编译器可以合理地生成a 1或a -1,具体取决于编译器调用这两个f()函数的顺序.