【问题标题】:Expression x[--i] = y[++i] = z[i++], which is evaluated first?表达式 x[--i] = y[++i] = z[i++],先计算哪个?
【发布时间】:2011-02-01 21:41:13
【问题描述】:

当左值的评估先于右值的评估并且赋值也返回一个值,以下哪个是首先评估的?

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 语言。 来自我的教科书

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

x = 2;

对这样一个命令的评估,在 除了将值 2 分配给 x, 返回值 2。因此,在 C 中, 我们也可以这样写:

y = x = 2;

应该解释为:

(y = (x = 2));

【问题讨论】:

  • 未定义的行为,我认为...
  • 另外,C 中不存在“越界”异常。而且,您的声明在语法上不正确。
  • 你肯定明白用“伪语言”要求语言规则是多么的没有意义。
  • 我在两个不同的编译器上编译了你的代码;使用 GCC(它警告i 上的操作可能未定义),在所有分配之后,i 等于 3。使用 Clang,i 在所有分配后等于 9。 Gremo,您需要了解评估序列和序列点是两个不同的概念。当您在一个序列点(在本例中为i)内多次修改变量时,行为未定义。
  • 主题有误导性,这个问题是周序点UB废话的重复。

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


【解决方案1】:

我很确定这种情况下的行为是未定义的,因为您在连续序列点之间多次修改和读取变量 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 在连续序列点之间被修改了多次,那么对于您的原始代码也可以这样说。赋值运算符不会引入新的序列点。

【讨论】:

  • 编辑问题,添加“伪语言”。
  • @Gremo:那你就得用你的伪语言标准来查找了。
【解决方案2】:

一般

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

i = i++;

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

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

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

具体

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

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

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

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

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

【讨论】:

  • 赋值运算符的结合性是从右到左的,所以上一个例子中的计算顺序是(x[i] = (y[i] = z[i]));
【解决方案3】:

我觉得和

一样
x[3] = y[4] = z[2];
i = 3;

【讨论】:

  • 这是一种可能的结果,但 C 标准不保证这一点;结果可能是雷暴和 35°C。未定义。
猜你喜欢
  • 2012-11-23
  • 1970-01-01
  • 2020-10-12
  • 1970-01-01
  • 2016-01-10
  • 1970-01-01
  • 2022-11-28
  • 2015-05-24
  • 2013-01-29
相关资源
最近更新 更多