如何确定C ++函数调用顺序?

时间:2015-06-07 08:31:49

标签: c++

我会跳过标题

class X {
    int i;
    static int j;

public:
    X(int ii = 1) : i(ii) {
        j = i;
    }
    static int incr() {
        return ++j;
    }
    static int f() {
        return incr();
    }
};

int _tmain(int argc, _TCHAR* argv[]) {
    X x;
    X* xp = &x;
    cout << x.f() << xp->f() << X::f();

    return 1;
}

此序列打印432,但在第一个视图中,可能会认为它将打印234。

如何确定函数调用的确切顺序?我错过了什么?

3 个答案:

答案 0 :(得分:2)

流运营商只是一个运营商。 C++ allows operators to be defined a multitude of ways.您所看到的是&lt;&lt;字符串的运算符。你正在做的是同样的事情:

cout << "word1" << "word2" << "word3";

期望输出为:

"word1word2word3"

然而,评估顺序由&lt;&lt;&lt;&lt;运营商。通常上述内容相当于:

   (((cout << "word1") << "word2") << "word3");

用函数替换字符串,你看到第一个被评估的字符串实际上是“word3”。这不是严格的情况,正如您通常会看到的那样。

   (((cout << func1()) << func2()) << func3());

评估顺序为func3,func2,func1,打印顺序为func1,func2,func3的返回。

答案 1 :(得分:2)

  

§1.9.13

     

之前排序的是由单个执行的评估之间的不对称,传递,成对关系       线程(1.10),它引起这些评估中的部分顺序。给出任何两个评估A和B,如果       A在B之前被排序,然后A的执行应该在B的执行之前。如果A之前没有排序       B和B在A之前未被测序,然后A和B未被测序。 [注:执行无序       评估可以重叠。 -end note]当A或A时,评估A和B是不确定的       在A或B之前对B或B进行测序之前对其进行测序,但未指定哪一种。 [注意:不确定       有序的评估不能重叠,但可以先执行。 - 后注]

换句话说,调用函数的顺序是Undefined。这并不意味着“我们不知道”,它并不意味着“你无法解决” - 这意味着它被定义为没有定义;编译器和cpu可以任意顺序完成它们。

请考虑以下事项:

int a[3];

void f1() { a[0] = 1; }
void f2() { a[1] = 2; }
void f3() { a[2] = 3; }

int main() {
    f1(), f2(), f3();
}

基本上,语言不要求在

之类的语句上进行排序
std::cout << f1() << f2() << f3();

您的代码在函数调用之间没有序列点(http://en.wikipedia.org/wiki/Sequence_point);你可以弄清楚你的编译器生成的顺序,但它可能在不同的CPU或不同的优化级别上表现不同。

如果您有类似的可变函数调用,则需要手动提升或添加中断:

std::cout << f1();
std::cout << f2();
std::cout << f3();

auto a1 = f1();
auto a2 = f2();
auto a3 = f3();
std::cout << a1 << a2 << a3;

答案 2 :(得分:1)

本声明

cout << x.f() << xp->f() << X::f();

可以像

一样重写
cout.operator <<( x.f() ).operator <<( xp->f() ).operator <<( X::f() );

未指定在此语句中用作参数的表达式的计算顺序。因此编译器可以例如从左到右或从右到左评估它们。因此,使用不同的编译器可以获得不同的结果。:)

要获得确定性结果,您应该重写语句

cout << x.f() << xp->f() << X::f();

例如

cout << x.f();
cout << xp->f();
coit << X::f();