1

当左值的求值先于右值的求值并且赋值也返回一个值时,以下哪个是最先求值的?

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?

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

在某些语言中,例如 C,赋值被认为是一个运算符,其评估除了产生副作用外,还返回由此计算的 r 值。因此,如果我们用 C 编写:

x = 2;

对这样一个命令的求值,除了将值 2 赋给 x 外,还返回值 2。因此,在 C 中,我们也可以这样写:

y = x = 2;

这应该解释为:

(y = (x = 2));
4

3 回答 3

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如果此语句由于在连续序列点之间多次修改而没有定义的行为,那么对于您的原始代码也可以这样说。赋值运算符不会引入新的序列点。

于 2011-02-01T21:46:12.183 回答
2

一般的

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

i = i++;

是未定义的行为。该标准定义了组成的事物列表sequence points,根据记忆,这是

  1. 语句后的分号
  2. 逗号运算符
  3. 在调用函数之前评估所有函数参数
  4. && 和 || 操作数

在维基百科上查找页面,列表更完整,描述更详细。序列点是 C 语言中一个非常重要的概念,如果您还不知道它的含义,请立即学习。

具体的

无论x,yz变量的求值和赋值顺序如何定义,对于

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

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

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

定义明确,但我不确定评估顺序的状态。如果这很重要,但是我宁愿将其拆分为两个语句以及注释“重要的是......在......之前被分配/初始化......因为......”。

于 2011-02-01T21:44:47.243 回答
-3

我认为它和

x[3] = y[4] = z[2];
i = 3;
于 2011-02-01T21:50:38.567 回答