首页 文章

打印东西时为什么不保留订单,首先是cerr然后是cout?

提问于
浏览
6

我有带有 Xubuntu 14.04的g版本4.8.4编译器 . 在我的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是缓冲的(这意味着,afai,cerr比cout慢);但是,无论如何,不应该改变执行的顺序?那个空白行从哪里来? (可能来自其中一个但是哪一个?)

有人可以解释这两行的内容吗?

非常感谢 .

EDIT: 我不使用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上工作 .

克里斯多德的第四个建议:

“你的代码实际上不是你上面发布的内容,而且差异虽然看似不重要,但实际上是至关重要的 . ”

当然,我的代码确实包含了我输入的内容以外的内容,但是有很多内容,我的意思是在这些行之前有很多计算等 . 但是,可能存在相关部分,在此之前我无法实现 . 此外,我没有将stdout和/或stderr重定向到这些行之前的不同设备/文件/管道 .

EDIT 2: 当我在Eclipse CDT的Debug模式下执行程序时,按照装配线,

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:当我注释掉这两行时,它按预期工作 . 因此,我的结论是,在这些行之前可能存在相关的代码部分,但我无法弄清楚它们 .

4 回答

  • 1

    这两行的顺序没有改变 . 但是,无论生成输出的代码是什么,您都看不到保存输出发送到两个流的顺序 . 它可能只是等待然后读取两个流以产生最终输出 . 如果不知道你的环境是什么样的话,很难确定 .

  • 1

    std::cerrstd::cout 是不同的流,它们不同步 . 所以你真的无法假设如何显示两者的输出 . 在这种情况下,输出恰好在错误之前显示 .

    您可以依赖任一流中的订单 .

    另外, std::cout 是缓冲的, std::cerr 不是,这通常会导致这种问题,但是因为你使用的是std :: endl(它会刷新流),所以这并不适用于你的情况 .

  • 5

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

    这意味着有很多可能性

    • 您的计算机坏了或编译器有问题(不太可能)

    • 你已经将 endl 定义为 std::endl 以外的其他东西,并且它没有试图被混淆

    • 你已经将stdout和/或stderr重定向到不同的设备/文件/管道,并且稍后将它们组合在一起,后来的组合步骤正在重新排序 .

    • 你的代码实际上不是你上面发布的内容,而且差异虽然看似不重要,但实际上是至关重要的 .

    因此,如果您想要真正回答这个问题,您需要发布并展示您实际在做什么 .

  • 2

    Eclipse CDT正在插入自己在创建进程期间进入 cerrcout 流 . 它可以将 cerr 流回显到其中一个窗口,然后写入预期的控制台 . 各种各样的发球台 .

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

相关问题