我正在写一些C++代码,用于娱乐和练习,以了解有关语言特性的更多信息。我想更多地了解静态变量及其在递归函数中的行为。在g++编译器中尝试这段代码,我得到了预期的结果:
#include <iostream>
using namespace std;
int f(const int& value)
{
static int result = 0;
return result += value;
}
int main()
{
cout << f(10) << ", " << f(f(10)) << ", " << f(f(f(10)));
return 0;
}但是我的朋友在MicrosoftVisualLinux6上测试了同样的代码,输出是50, 80, 90,我用其他的C++编译器(g++,Borland,C++::blocks和MingW在Linux,Win和Mac下测试的)输出是110, 100, 40。我不明白输出怎么会是50, 80, 90 ...
为什么MSVC的输出是不同的?
发布于 2011-03-02 01:28:40
以下三个子表达式的求值顺序未指定:
f(10)
f(f(10))
f(f(f(10)))编译器可以按任何顺序对这些子表达式求值。您不应该在程序中依赖于特定的求值顺序,特别是当您打算使用多个编译器进行编译时。
这是因为该表达式中的任何位置都没有序列点。唯一的要求是在需要结果之前(即打印结果之前)对每个子表达式进行求值。
在您的示例中,实际上有几个子表达式,我在这里将其标记为a到k:
// a b c d e f g h i j k
cout << f(10) << ", " << f(f(10)) << ", " << f(f(f(10)));对operator<< (a、c、d、g和h)的调用都必须按顺序进行计算,因为每个调用都依赖于前一次调用的结果。同样,在评估a之前必须先评估b,在评估j、i或h之前必须评估k。
但是,这些子表达式之间没有依赖关系:b的结果不依赖于k的结果,因此编译器可以自由生成代码,该代码先计算k,然后计算b,或者先计算b,然后计算k。
有关序列点和相关的未指定和未定义行为的更多信息,请考虑阅读堆栈溢出C++常见问题解答文章"Undefined Behavior and Sequence Points" (您的程序没有任何未定义的行为,但该文章的大部分内容仍然适用)。
发布于 2011-03-02 01:33:35
仅仅因为输出在屏幕上从左到右出现并不意味着评估的顺序遵循相同的方向。在C++中,函数参数的计算顺序未指定。另外,通过<<操作符打印数据只是调用函数的花哨语法。
简而言之,如果您说operator<<(foo(), bar()),编译器可以首先调用foo或bar。这就是为什么调用有副作用的函数并将其用作其他函数的参数通常不是一个好主意。
发布于 2011-03-02 01:40:48
一种简单的方法来查看它到底在做什么:
int f(const int& value, int fID)
{
static int result = 0;
static int fCounter = 0;
fCounter++;
cout << fCounter << ". ID:" << fID << endl;
return result += value;
}
int main()
{
cout << f(10, 6) << ", " << f(f(10, 4), 5) << ", " << f(f(f(10, 1),2),3);
return 0;
}我同意其他人在他们的答案中所说的,但这将让你确切地看到它在做什么。:)
https://stackoverflow.com/questions/5158014
复制相似问题