为什么在打印某些内容时不保留顺序,首先使用 cerr 然后使用 cout?

Why the order is not preserved when printing something, first with cerr and then cout?

我有 g++ 版本 4.8.4 编译器和 Xubuntu 14.04。在我的OpenCV代码中(用Eclipse写的CDT),我连续写了下面三行:

/* Some codes here*/
cerr << "No match found. # of false positives: " << falsePositives << endl;
cout << "Press a key to continue..." << endl;
waitKey(0);

结果如下:

Press a key to continue...
No match found. # of false positives: 1
/*there is a blank line*/

为什么这两行的顺序在执行时改变了?前面几行中根本没有并行代码,但它们似乎(同时)并行工作。

我知道 cerr 没有缓冲,而 cout 有缓冲(这意味着,据我所知,cerr 比 cout 慢);但是,不管怎样,执行的顺序不应该改变一下吗?那个空行是从哪里来的? (可能来自其中一个结尾,但是哪一个?)

谁能解释一下这两行是怎么回事?

非常感谢。

编辑: 我不使用ubuntu,我使用Xubuntu 14.04。对不起那个错误,我的头脑太乱了,但我认为这不会影响结果。 我使用 Eclipse 提供的控制台来显示它们。我试图将 std:: 前缀附加到所有 cout、cerr、endl。结果是一样的。

有趣的一点是,当我刚刚写了一个新文件包括:

#include <iostream>
#include <cstdlib>
int main()
{       
    std::cerr << "No match found. # of false positives: " << 2 << std::endl;
    std::cout << "Press a key to continue..." << std::endl;

    return 0;
}

我通过使用 xfce4-terminal 和 g++ 编译器获得了预期的输出(首先是 cerr,然后是 cout)。

使用 Eclipse 时出现问题 CDT。我还想提醒大家,我在 OpenCV 上工作。

Chris Dodd 的第四条建议:

"your code is actually something other than what you've posted above, and the difference, while seemingly unimportant, is actually crucial."

当然,我的代码确实包含我输入的内容以外的内容,但在这些行之前有很多,我的意思是很多计算等。但是,可能有一些相关的部分是我之前无法意识到的。另外,我根本没有在这些行之前将 stdout and/or stderr 重定向到不同的 devices/files/pipes。

编辑 2: 当我在 Eclipse CDT 的调试模式下执行程序时,遵循装配线,

cerr 行之后执行以下代码(当然还有其他汇编代码):

callq 0x403500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
callq 0x403470 <_ZNSolsEi@plt>
callq 0x403770 <_ZNSolsEPFRSoS_E@plt>

cout 行之后执行以下代码(当然还有其他汇编代码):

callq 0x403500 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
callq 0x403770 <_ZNSolsEPFRSoS_E@plt>
callq 0x403670 <_ZN2cv7waitKeyEi@plt>

他们都给出相同的错误信息:

"std::basic_ostream >& std::operator<< >(std::basic_ostream >&, char const*)@plt at 0x403500"

没有可用的资源

并且该过程继续其他行的汇编代码而不会终止。

PS:当我注释掉除这两行以外的所有内容时,它按预期工作。因此,我的结论是,在这些行之前可能有相关的代码部分,但我无法弄明白。

std::cerrstd::cout是不同的流,不同步。 所以你真的不能假设任何关于如何显示两者的输出。在这种情况下,输出恰好在错误之前显示。

可以依赖任一流中的顺序。

此外,std::cout 是缓冲的而 std::cerr 不是,这通常会导致此类问题,但是因为您使用的是 std::endl(它会刷新流)所以不会'真的适用于你的情况。

这两行的顺序没有改变。但是,无论生成您看到的输出的代码都无法保留将输出发送到两个流的顺序。它可能只是等待然后读取两个流以产生最终输出。在不知道您的环境是什么样子的情况下很难确定。

好吧,std::endl 将流刷新到底层设备,这意味着输出 不能 合法地成为您所描述的 - 第一个 endl在输出到 cout 之前排序,因此 cerr 必须 被刷新并且在执行第二行之前输出出现在终端上。

这意味着有多种可能性

  • 你的电脑坏了或编译器有问题(不太可能)
  • 您已将 endl 定义为 std::endl 以外的其他内容,并且它不会刷新(如果您试图混淆,则可能)
  • 你已经将 stdout and/or stderr 重定向到不同的 devices/files/pipes 并且稍后将它们组合,后面的组合步骤是重新排序。
  • 您的代码实际上与上面 post 编写的不同,差异虽然看似不重要,但实际上至关重要。

因此,如果您想真正回答这个问题,您需要 post 和 MVCE 证明您实际在做什么。

Eclipse CDT 在您的进程创建期间将自身插入到 cerrcout 流中。它可能会将 cerr 流回显到其 windows 之一,然后写入预期的控制台。各种各样的发球台。

由于正在轮询这些流,因此无法同步它们。这可以解释这种行为。