Russian Qt Forum

Qt => Общие вопросы => Тема начата: 8Observer8 от Июль 31, 2014, 20:02



Название: Вывод в консоль
Отправлено: 8Observer8 от Июль 31, 2014, 20:02
Привет!

Столкнулся со странным поведением. В примере ниже вывожу в консоль имена файлов и папок текущего каталога:

Код
C++ (Qt)
#include <iostream>
#include <QDir>
#include <QStringList>
#include <QDebug>
 
int main()
{
   QDir dir( QString( "./" ) );
   QStringList list = dir.entryList();
   foreach (QString s, list) {
       qDebug() << s;
       std::cout << s.toStdString() << std::endl;
   }
}
 

Ожидаю увидеть:
Цитировать
"."
.
".."
..
"debug"
debug
"Makefile"
Makefile
"Makefile.Debug"
Makefile.Debug
"Makefile.Release"
Makefile.Release
"release"
release

Bижу:
Цитировать
"."
.
".."
"debug"
"Makefile"
"Makefile.Debug"
..
debug
Makefile
Makefile.Debug
Makefile.Release
release
"Makefile.Release"
"release"

Заранее спасибо за ответ!


Название: Re: Вывод в консоль
Отправлено: gil9red от Июль 31, 2014, 20:10
UPDATE.
Не в тему...


Название: Re: Вывод в консоль
Отправлено: 8Observer8 от Июль 31, 2014, 20:24
Точки не интересуют :) Почему не по парам?


Название: Re: Вывод в консоль
Отправлено: 8Observer8 от Июль 31, 2014, 20:32
Другой пример:

Код
C++ (Qt)
 
#include <iostream>
#include <QDir>
#include <QStringList>
#include <QDebug>
 
int main()
{
   QDir dir( QString( "./" ) );
   QStringList list = dir.entryList( QDir::NoDotAndDotDot | QDir::Dirs );
   foreach (QString s, list) {
       qDebug() << s;
       std::cout << s.toStdString() << std::endl;
   }
}
 

Output
Цитировать
"debug"
debug
release
"release"

А должно быть:
Цитировать
"debug"
debug
"release"
release


Название: Re: Вывод в консоль
Отправлено: Serr500 от Июль 31, 2014, 20:37
А с чего Вы решили, что так должно быть? Почему Вы думаете, что qDebug совпадает с std::cout?


Название: Re: Вывод в консоль
Отправлено: 8Observer8 от Июль 31, 2014, 20:59
Инструкции должны выполняться поочереди: сначала qDebug, потом std::cout


Название: Re: Вывод в консоль
Отправлено: Serr500 от Июль 31, 2014, 21:03
А они по очереди и выполняются.  ;)

Подсказки Вы не поняли. Попробую по другому.

1) Для чего нужен std::flush?
2) qDebug() << "..." в итоге обращается к qt_message_print, который выводит в stderr через printf.


Название: Re: Вывод в консоль
Отправлено: Serr500 от Июль 31, 2014, 21:17
Ладно уж, я сегодня добрый.

Операторы вывода в консоль выполняют вывод не сразу. Они сохраняют выводимые строки в свой внутренний буфер, который потом сбрасывают (flush), после чего вывод появляется в консоли. Сброс происходит не сразу. Если выводить в разные потоки, то сброс может выполняться в обратном порядке, поэтому строки также могут поменять порядок. Как я уже сказал, qDebug выводит в stderr, который отличается от std::cout.

В качестве примера попробуйте выполнить следующий код:
Код:
    std::cout << "String 1";
    fprintf(stderr, "String 2");

    fflush(stderr);
    std::cout << std::flush;

Несмотря на то, что вывод "String 1" выполняется раньше вывода "String 2", в консоли мы увидим строки в обратном порядке.


Название: Re: Вывод в консоль
Отправлено: Hrundel от Июль 31, 2014, 23:45
[off-top]

Вот и пообщались "хакер" и "хакер" :D


Название: Re: Вывод в консоль
Отправлено: 8Observer8 от Август 01, 2014, 13:17
Спасибо! Всё равно, как это неправильно... Я как пользователь фреймворка, если написал qDebug() первым, он должен так и сработать. Почему же интересно разработчики не учли и flush() не вызывается.

Если вызвать "fflush(stderr);" и "std::cout.flush();" то всё равно выводит непарно:

Код
C++ (Qt)
 
#include <iostream>
#include <QDir>
#include <QStringList>
#include <QDebug>
 
int main()
{
   QDir dir( QString( "./" ) );
   QStringList list = dir.entryList( ); // QDir::NoDotAndDotDot | QDir::Dirs
   foreach (QString s, list) {
       qDebug() << s;
       fflush(stderr);
       std::cout << s.toStdString() << std::endl;
       std::cout.flush();
   }
}
 


Название: Re: Вывод в консоль
Отправлено: navrocky от Август 01, 2014, 19:13
Предполагаю, что, так как твоё приложение и терминал это разные процессы, которые работают асинхронно, считывание двух потоков std::out и std::err терминалом происходит не синхронно, вот ты и видишь разницу.

Возможно это поведение зависит от используемого эмулятора терминала и операционки.

Вариант решения - перехватить вывод qDebug с помощью qInstallMsgHandler() и направить его в std::out.


Название: Re: Вывод в консоль
Отправлено: 8Observer8 от Август 01, 2014, 19:18
Спасибо! Стало понятней. Так-то это не особо важно. Просто интересно было узнать, что примерно происходит :)