a + b + c会这样操作:a + c + b?

时间:2011-04-07 14:07:17

标签: c

正如我们所知道的:评估的顺序取决于优先级和相关性。 对于此示例,关联性确定a + b,然后结果加c。这是符合ANSI C标准的编译器所做的(省略优化)。但是它会像标题中的前述方式一样进行评估吗?在什么编译器?在K& R C?

6 个答案:

答案 0 :(得分:4)

让我向你抛出这个:

Operator Precedence vs Order of Evaluation

答案 1 :(得分:2)

只要最终结果相同,编译器就可以自由重新排列。

例如:

1 + b + 1

可以轻松转换为:

b + 2

答案 2 :(得分:1)

用数学术语表示的等式结构(在a+(b*c)中我们讨论b*c被评估为“第一”)并不一定与编译器评估参数的顺序有关

此实例中的实际执行顺序是未定义的IIRC。 C只保证由序列点分隔的表达式的顺序保持不变,+运算符不是序列点。

大多数编译器都会按预期执行 - 生成代码然后评估a b然后c

答案 3 :(得分:1)

n1256

6.5表达
...
3运算符和操作数的分组由语法指示。 74)除非另有说明 稍后(对于函数调用()&&||?:和逗号运算符),评估顺序 子表达式和发生副作用的顺序都是未指明的
...
74)语法指定运算符在表达式求值中的优先级,它是相同的 作为本条款主要子条款的顺序,首先是最高优先级。因此,例如, 表达式允许二进制+运算符(6.5.6)的操作数是在中定义的表达式 6.5.1至6.5.6。例外情况是强制转换表达式(6.5.4)作为一元运算符的操作数 (6.5.3),以及以下任何一对运算符之间包含的操作数:分组 括号()(6.5.1),下标括号[](6.5.2.1),函数调用括号()(6.5.2.2),以及 条件运算符?:(6.5.15)。

在每个主要子条款中,运算符具有相同的优先级。左或右相关性是 在每个子条款中通过其中讨论的表达式的语法表示。

强调我的。表达式a + b + c将被评估为(a + b) + c;也就是说,c结果将添加到a + b结果中。在评估a之前,必须先评估ba + b,但可以按任意顺序评估abc

答案 4 :(得分:0)

a + b + c == c + b + a

订单无关紧要。

它被称为operator precedence

答案 5 :(得分:0)

我会尝试强调您认为评估顺序与编译器认为的差异。

在数学上我们说在表达式a + b * c中,在加法之前计算乘法。当然必须是因为我们需要知道要添加到a的内容。

但是,编译器在评估b * c之前不一定要考虑评估表达式a。您可能认为因为乘法具有更高的优先级,所以编译器将首先查看表达式的该部分。实际上,无法保证编译器将首先决定做什么。它可以先评估a,或bc。标准未指定这种行为。

为了演示,我们来看看以下代码:

#include <iostream>

int f() { std::cout << "f\n"; return 1; }
int g() { std::cout << "g\n"; return 2; }
int h() { std::cout << "h\n"; return 3; }

int main(int argc, const char* argv[])
{
  int x = f() + g() * h();
  std::cout << x << std::endl;
  return 0;
}

每个函数f()g()h()只是将函数的名称输出到标准输出,然后分别返回1,2或3。

当程序启动时,我们将变量x初始化为f() + g() * h()。这正是我们之前看到的表达方式。答案当然是7.现在,天真地你可以假设乘法首先发生,所以它会去那里它会g(),然后乘以h(),然后它会执行f()并将其添加到上一个结果中。

实际上,使用GCC 4.4.5进行编译会告诉我,函数按照它们在表达式中出现的顺序执行:f(),然后是g(),然后是h()。这并不是所有编译器都必须发生的事情。这完全取决于编译器如何做到这一点。

如果您正在执行关联或可交换的操作,那么编译器也可以自由地交换表达式中的数学分组,但仅当结果正好他们是一样的。编译器必须小心,不要进行任何可能导致溢出发生的重组,而这些重组都不会发生。只要结果是标准定义的,编译器就可以自由地做它想做的事情。