的逗号序列操作者引入了一个顺序点的表达式中。 我想知道这是否意味着,下面的程序避免不确定的行为。
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
如果它避免不确定的行为,它可能仍然是不确定,就是返回几个可能值之一。 我认为,在C99,它只能计算1
,但实际上,GCC的各种版本编译这个程序将返回一个可执行文件2
。 锵生成返回一个可执行文件1
,用我的直觉显然同意。
最后,就是这个东西,在C11改变?
的逗号序列操作者引入了一个顺序点的表达式中。 我想知道这是否意味着,下面的程序避免不确定的行为。
int x, y;
int main()
{
return (x++, y) + (y++, x);
}
如果它避免不确定的行为,它可能仍然是不确定,就是返回几个可能值之一。 我认为,在C99,它只能计算1
,但实际上,GCC的各种版本编译这个程序将返回一个可执行文件2
。 锵生成返回一个可执行文件1
,用我的直觉显然同意。
最后,就是这个东西,在C11改变?
就拿表达式:
(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
没有什么在这个禁止该标准的,所以整个事情是未定义行为。
对比这伪代码:
f() { return x++, y; }
g() { return y++, x; }
f() + g()
Acoording至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
由于执行f
计数作为副作用本身,在该序列点g()
暂停执行,直到f
已经返回。 因此,没有任何不确定的行为。
该标准的全篇6.5提及评价的顺序,运营商的基础上。 我能找到评估秩序的最好的总结是标准的(非规范)附件J:
C11附件J
J.1未指定的行为
- (6.5),和逗号运营商:其中的子表达式的计算顺序,并且其中的副作用发生,除了作为函数调用()指定的,&&,||,订单?
在你的例子,可以不知道是否子表达式(x++, y)
或(y++, x)
首先被评估,因为+运算的操作数的计算顺序是不确定的。
至于不确定的行为,逗号运算解决什么。 如果(x++, y)
先计算,然后y
可能会立即之前评价y++
其他子表达的。 因为y是在之间,没有一个顺序点访问两次用于其他目的,而不是确定的值来存储,该行为是未定义的。 这里更多的信息。
所以,你的程序不定,不确定的行为两者。
(另外,它具有实现定义的行为,因为INT主要(),而不是INT主要(无效)不是主要的托管应用的良好定义的版本之一。)
我的理解是,任何下面的评测命令是合法的:
x++, y++, y, x
x++, y, y++, x
x++, y++, x, y
y++, x, x++, y
但不是:
y, x++, x, y++
在我的理解,这是唯一需要的顺序是(x++)
前一定要来(y)
和(y++)
必须出现在(x)
因此,我认为,这仍然是不确定的行为。
标准中明确声明了运营商引入序列点, +
不在其中。 所以,你的表达能很好的方式认定是禁止的子表达式求值“接近”对方,没有它们之间的序列点。
上的语用的基础上,存在用于此遮断一个原因,即这样的操作的操作数的评价可以并行,例如被调度如果处理器具有用于所讨论的子表达式的操作数管线。 您可以轻松地说服自己,评价这样的模式下,任何事情都有可能发生,其结果是不可预测的。
在你的玩具例子,冲突是可以预见的,但不一定是,如果你将在子表达式使用一些间接指针的情况。 那么你就不会知道,如果子表达式中的一个将潜在的别名等。 因此,基本上没有多少,如果它要允许这种类型的优化C能做到。