函数调用顺序
为了表达
(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; }
您无法对调用这些函数的顺序做出任何假设。 编译器以任何顺序调用这些函数,将结果分配给临时值,然后使用这些临时值来计算表达式的结果,这是完全有效的。
这些调用可以按任何顺序进行。 你想了解 C ++序列点 C ++序列点 。
很自然地认为在这个psudocode中C
之前评估A+B
:
(A+b)*C
但事实上并非如此。 标准规定,除非标准另有规定,否则所有表达式的评估顺序均为“未指定”:
5/4 [expr]:
除非另有说明,否则单个运算符的操作数和各个表达式的子表达式的评估顺序以及副作用发生的顺序是未指定的。
然后,标准继续将带括号的表达式标识为“主要表达式”,但不指定主要表达式的评估顺序。 (5.1 / 5)。
在Standardese中,“未指定”并不意味着“未定义”。 相反,它意味着“实施定义,但不需要文档。” 所以你甚至可能无法说出特定编译器的评估顺序。
这是一个简单的程序,说明了行为:
#include #include 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"); }
在Win7上运行在Debug / x64上的MSVC10上,输出恰好是:
'C'(1) 'B'(2) 'A'(3) 'A+B'(4) 'A+B+C'(5)
C / C ++中的括号强制操作顺序。 func1() * func2()
将添加到func3()
,但编译器可以选择在将结果传递给乘法/加法运算之前以任何顺序调用函数。