表达式x [ - i] = y [++ i] = z [i ++],首先进行评估?

时间:2011-02-01 21:41:14

标签: c variable-assignment operator-precedence undefined-behavior

当l值的评估先于评估r值时,分配返回一个值,首先评估以下哪个值?

int i = 2;
int x[] = {1, 2, 3};
int y[] = {4, 5, 6};
int z[] = {7, 8, 9};

x[--i] = y[++i] = z[i++]; // Out of bound exception or not?

注意:通用的C语言,首先是l值评估。 从我的教科书

  

在某些语言中,例如C,   任务被认为是一种   另外,运营商的评估   也产生副作用   返回如此计算的r值。   因此,如果我们用C编写:

x = 2;
  

评估这样一个命令   除了将值2赋值给x之外,   返回值2.因此,在C中,   我们也可以写:

y = x = 2;
  

应解释为:

(y = (x = 2));

3 个答案:

答案 0 :(得分:6)

我非常确定这种情况下的行为是未定义的,因为您在连续序列点之间多次修改和读取变量i的值。

此外,在C中,通过将[]放在变量名之后而不是在类型之后声明数组:

int x[] = {1, 2, 3};

编辑:

从示例中删除数组,因为它们[大部分]无关紧要。现在考虑以下代码:

int main(void)
{
    int i = 2;
    int x = --i + ++i + i++;
    return x;
}

此代码演示了对原始代码中的变量i执行但没有数组的操作。您可以更清楚地看到变量i在此语句中被多次修改。当您依赖于在连续序列点之间修改的变量的状态时,行为是未定义的。不同的编译器(并且GCC返回6,Clang返回5)会给出不同的结果,并且相同的编译器可以使用不同的优化选项给出不同的结果,或者根本没有明显的原因。

如果此语句没有定义的行为,因为i在连续序列点之间被多次修改,那么对于原始代码也可以这样说。赋值运算符不会引入新的序列点。

答案 1 :(得分:2)

常规

在C中,两个sequence points之间的任何操作的顺序都不应该依赖于。我不记得标准中的确切措辞,但出于这个原因

i = i++;

是未定义的行为。该标准定义了组成sequence points的事物列表,从内存中可以看出

  1. 声明后的分号
  2. 逗号运算符
  3. 在调用函数之前评估所有函数参数
  4. &&和||操作数
  5. 在维基百科上查找页面,列表更完整,更详细地描述。序列点是C中非常重要的概念,如果您还不知道它的含义,请立即学习。

    具体

    无论评估和分配xyz变量的顺序如何明确,

    x[--i] = y[++i] = z[i++];
    

    由于i--i++i++,此语句不能是未定义的行为。 另一方面

    x[i] = y[i] = z[i];
    

    定义明确,但我不确定此评估顺序的状态。如果这很重要,我宁愿把它分成两个语句,同时注释“重要的是......在...之前分配/初始化......因为......”。

答案 2 :(得分:-3)

我认为它与

相同
x[3] = y[4] = z[2];
i = 3;