C 是(x+;+;,y)+;(y+;+;,x)未定义或未指定,如果未指定,它可以计算什么?
在表达式中引入。我想知道这是否意味着下面的程序避免了未定义的行为C 是(x+;+;,y)+;(y+;+;,x)未定义或未指定,如果未指定,它可以计算什么?,c,c99,language-lawyer,c11,unspecified-behavior,C,C99,Language Lawyer,C11,Unspecified Behavior,在表达式中引入。我想知道这是否意味着下面的程序避免了未定义的行为 int x, y; int main() { return (x++, y) + (y++, x); } 如果它确实避免了未定义的行为,它仍然可能是未指定的,也就是说,返回几个可能的值之一。我认为在C99中,它只能计算1,但实际上,各种版本的GCC将该程序编译成返回2的可执行文件。Clang生成一个返回1的可执行文件,显然符合我的直觉 最后,这在C11中是否发生了变化?我的理解是,以下任何评估命令都是合法的: x++,y
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
如果它确实避免了未定义的行为,它仍然可能是未指定的,也就是说,返回几个可能的值之一。我认为在C99中,它只能计算1
,但实际上,各种版本的GCC将该程序编译成返回2
的可执行文件。Clang生成一个返回1
的可执行文件,显然符合我的直觉
最后,这在C11中是否发生了变化?我的理解是,以下任何评估命令都是合法的:
x++,y++,y,x
x++,y,y++,x
x++,y++,x,y
y++,x,x++,y
y,x++,x,y++
(x++)
必须在(y)
之前,并且(y++)
必须在(x)
之前
因此,我认为这仍然是未定义的行为。我的理解是,以下任何评估命令都是合法的:
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
x++,y++,y,x
x++,y,y++,x
x++,y++,x,y
y++,x,x++,y
y,x++,x,y++
(x++)
必须在(y)
之前,并且(y++)
必须在(x)
之前
因此,我认为这仍然是未定义的行为。采用以下表达式:
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
(x++, y) + (y++, x)
从左到右求值:
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
标准中没有禁止这一点,所以整件事都有未定义的行为
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
对比此伪代码:
f() { return x++, y; }
g() { return y++, x; }
f() + g()
a根据C99(5.1.2.3/2),对f
和g
的调用本身被视为副作用,函数调用操作符在进入函数之前包含一个序列点。这意味着函数执行不能交错
在“并行评估”模式下:
由于执行f
本身算作副作用,因此g()
中的序列点暂停执行,直到f
返回。因此,没有未定义的行为。采用以下表达式:
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
(x++, y) + (y++, x)
从左到右求值:
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
标准中没有禁止这一点,所以整件事都有未定义的行为
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
对比此伪代码:
f() { return x++, y; }
g() { return y++, x; }
f() + g()
a根据C99(5.1.2.3/2),对f
和g
的调用本身被视为副作用,函数调用操作符在进入函数之前包含一个序列点。这意味着函数执行不能交错
在“并行评估”模式下:
由于执行
f
本身算作副作用,因此g()
中的序列点暂停执行,直到f
返回。因此,没有未定义的行为。整个标准第6.5章都提到了基于操作员的评估顺序。我能找到的关于评估顺序的最佳总结是标准的(非规范性)附录J:
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
C11附件J
J.1未指明的行为
- 子表达式的求值顺序和副作用发生的顺序,除非为 函数调用()、&&、| |、?:、和逗号运算符(6.5)
(x++,y)
还是(y++,x)
,因为+运算符的操作数的计算顺序未指定
至于未定义的行为,逗号运算符没有解决任何问题。如果首先计算(x++,y)
,则可以在另一个子表达式的y++
之前立即计算y
。由于y被访问两次,其间没有一个序列点,因此除了用于确定要存储的值之外,该行为是未定义的
因此,您的程序同时具有未定义和未指定的行为
(此外,它具有实现定义的行为,因为int main()而不是int main(void)不是托管应用程序中定义良好的main版本之一。)整个标准第6.5章都提到了基于操作员的评估顺序。我能找到的关于评估顺序的最佳总结是标准的(非规范性)附录J: C11附件J J.1未指明的行为
- 子表达式的求值顺序和副作用发生的顺序,除非为 函数调用()、&&、| |、?:、和逗号运算符(6.5)
(x++,y)
还是(y++,x)
,因为+运算符的操作数的计算顺序未指定
至于未定义的行为,逗号运算符没有解决任何问题。如果首先计算(x++,y)
,则可以在另一个子表达式的y++
之前立即计算y
。由于y被访问两次,其间没有一个序列点,因此除了用于确定要存储的值之外,该行为是未定义的
因此,您的程序同时具有未定义和未指定的行为
(此外,它具有实现定义的行为,因为int main()而不是int main(void)不是托管应用程序中定义良好的main版本之一。)该标准明确声明了哪些操作符引入序列点,
+
不在其中。所以你的表达可以是evalu