C++编译器命令顺序不一致。

3

我尝试运行一个简单的C++程序,但不确定为什么不同的编译器提供不同的输出结果。

#include <iostream>

struct A
{
    A() { std::cout << "Object A created" << std::endl; }

    friend std::ostream& operator<<(std::ostream& os, const A& a)
    {
        os << a.str << "\n";
        return os;
    }

    static bool printMe()
    {
        std::cout << "static bool printMe() of object A" << std::endl;
        return true;
    }
    std::string str{"This is object A"};
};


int main()
{
    std::cout << A() << (A::printMe() ? "TRUE" : "FALSE") << std::endl;
}

输出1:一些编译器提供以下输出:

Object A created
This is object A
static bool printMe() of object A
TRUE

例如: https://www.programiz.com/cpp-programming/online-compiler/ 输出2:其他编译器会提供不同的输出。
static bool printMe() of object A
Object A created
This is object A
TRUE

例如: http://cpp.sh/ 我不理解为什么某些编译器会在创建对象A之前执行静态函数,我期望的顺序是保持不变,即在调用静态函数之前创建对象A,就像OUTPUT2中一样。

1
C++ 不保证这一点。 - Daniel A. White
如果您想要定义顺序,请指定-std=c++17。请参阅评估顺序 cout << i << i++; // 在C++17之前为未定义行为 - 273K
如果我无法切换到C++17,是否有任何编译器标志可以强制执行此顺序? - ol202020
1
@273K,所呈现的代码顺序是未指定的,而不是未定义的。在您的示例中,UB来自以未指定的顺序修改i - Quimby
1
基本上,编译器保证插入操作(重载的位移运算符)发生的顺序,但是它计算要插入的值的时间只能保证在插入之前的某个时刻。实际上有三种合法的顺序 -- cout << f() << g() 可以与 auto e1 = f(); auto e2 = g(); cout << e1; cout << e2; 或者 auto e1 = f(); cout << e1(); auto e2 = g(); cout << e2; 相同,或者是你看到的那个 auto e2 = g(); auto e1 = f(); cout << e1; cout << e2; - Ben Voigt
1个回答

6
在C++17之前,表达式中子表达式的评估顺序大多是未指定的,编译器可以根据其自己的意愿对它们进行排序。 在C++17中,顺序更加严格定义,特别地:
在移位运算符表达式E1<>E2中,E1的每个值计算和副作用都在E2的每个值计算和副作用之前发生[cppreference]
因此,如果您添加了-std=c ++ 17,则应仅看到OUTPUT1。
'?'的顺序一直是已定义的,所以很安全。

1
另外,请注意函数参数的评估顺序仍未指定。原因是这样可以让编译器在某些情况下更好地优化代码。 - digito_evo
2
你确定我应该使用C++17来查看OUTPUT2吗? 我已经使用这个编译器设置为C++17并得到了OUTPUT1。 - ol202020
1
@ol202020 抱歉,应该是OUTPUT1,求值顺序基本上是从左到右。 - Quimby
1
@ol202020:编译器不关心代码行数,它只关心完整表达式(由分号分隔)。 - Ben Voigt
谢谢,Ben。我知道这个问题,只是想知道是否有任何编译器标志可以强制从左到右进行评估,但我猜没有。 - ol202020
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接