Pas*_*uoq 1 c c99 language-lawyer unspecified-behavior c11
的逗号序列操作者引入了一个顺序点的表达式中.我想知道这是否意味着下面的程序避免了未定义的行为.
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
Run Code Online (Sandbox Code Playgroud)
如果它确实避免了未定义的行为,它仍然可能未指定,即返回几个可能值中的一个.我认为在C99中,它只能计算1,但实际上,各种版本的GCC将此程序编译成可返回的可执行文件2.Clang生成一个返回的可执行文件1,显然与我的直觉一致.
最后,这是C11改变了吗?
拿表达式:
(x++, y) + (y++, x)
Run Code Online (Sandbox Code Playgroud)
从左到右评估:
x++ // yield 0, schedule increment of x
, // sequence point: x definitely incremented now
y // yield 0
y++ // yield 0, schedule increment of y
// explode because you just read from y and wrote to y
// with no intervening sequence point
Run Code Online (Sandbox Code Playgroud)
标准中没有任何内容禁止这样做,因此整个事情都有未定义的行为.
对比这个伪代码:
f() { return x++, y; }
g() { return y++, x; }
f() + g()
Run Code Online (Sandbox Code Playgroud)
根据C99(5.1.2.3/2),调用f和g自身计为副作用,函数调用运算符在进入函数之前包含一个序列点.这意味着函数执行不能交错.
在"并行评估"模型下:
f() // arbitrarily start with f: sequence point; enter f
g() // at the same time, start calling g: sequence point
Run Code Online (Sandbox Code Playgroud)
由于f计数作为副作用本身g()执行,序列点暂停执行直到f返回.因此,没有未定义的行为.
标准的第6.5章提到了运营商的评估顺序.我能找到的评估顺序的最佳总结是该标准的(非规范性)附件J:
C11附件J.
J.1未指定的行为
- 除了为函数调用(),&&,||,?:和逗号运算符(6.5)指定的情况外,评估子表达式的顺序和副作用的顺序除外
在你的榜样,你无法知道是否有子表达式(x++, y)或(y++, x)先评估,因为+运算符的操作数的计算顺序是不确定的.
至于未定义的行为,逗号运算符什么也没解决.如果(x++, y)首先进行评估,则y可以y++在另一个子表达式之前立即进行评估.由于y被访问两次而中间没有序列点,出于其他目的而不是确定要存储的值,行为是未定义的.更多信息在这里.
所以你的程序都有未定义和未指定的行为.
(此外,它具有实现定义的行为,因为int main(),而不是int main(void)不是托管应用程序中明确定义的main版本之一.)