针对这个表达式
(func1() * func2()) + func3()
func1() * func2()会首先被计算,因为它有括号。但是函数的调用顺序可以随意,比如先调用func3(),然后再计算(func1() * func2())。
运算符的优先级与操作数的求值顺序无关。
C或C++标准不确定函数调用的顺序。
子表达式的求值顺序包括:
, +, -, =, *, /
),但以下运算符除外:
&&
和||
)?:
),
)是未指定的。
例如:
int Hello()
{
return printf("Hello"); /* printf() returns the number of
characters successfully printed by it
*/
}
int World()
{
return printf("World !");
}
int main()
{
int a = Hello() + World(); //might print Hello World! or World! Hello
/** ^
|
Functions can be called in either order
**/
return 0;
}
您不能假设这些函数调用的顺序。编译器完全可以以任何顺序调用这些函数,将结果分配给临时变量,然后使用这些临时值计算表达式的结果。
自然而然地认为在这个伪代码中,A+B
在 C
之前被计算:
(A+b)*C
但实际上并非如此。标准规定所有表达式的计算顺序都是“未指定的”,除非标准另有规定:
除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的计算顺序以及副作用发生的顺序均为未指定
标准接着将括号表达式标识为“基本表达式”,但不指定基本表达式的计算顺序(5.1 / 5)。
在标准术语中,“未指定”并不意味着“未定义”。它表示“实现定义,但不需要文档记录”。因此,您甚至可能无法确定特定编译器的计算顺序。
下面是一个简单的程序,说明了这种行为:
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
Foo(const string& name) : name_(name) {++i_; cout << "'" << name << "'(" << i_ << ")\n"; };
operator unsigned() const { return i_; }
Foo operator+(const Foo& rhs) const { string new_name = name_; new_name += "+"; new_name += rhs.name_; return Foo(new_name); }
private:
string name_;
static unsigned i_;
};
unsigned Foo::i_ = 0;
int main()
{
(Foo("A") + Foo("B")) + Foo("C");
}
'C'(1)
'B'(2)
'A'(3)
'A+B'(4)
'A+B+C'(5)
C/C++中的括号强制指定运算顺序。 func1() * func2()
将会先被加到 func3()
中,但编译器可以在将结果传递给乘法/加法运算之前以任何顺序调用函数。