Программисты, у которых в коде используются функции языка СИ printf() / fprintf(), замечают, что такой вывод в консоль появляется со значительной задержкой (до нескольких секунд) в окне "Вывод приложения" QtCreator-а. Если это же приложение запустить в любом терминале, от xterm до konsole, то такой проблемы не будет.
Этот баг окна вывода QtCreator появлялся в 3-м и в 4-м креаторе, его исправляли, и снова ломали, в общем, в арсенале Qt-программиста должно быть решение, как эту проблему можно обойти.
Примечание. Кому вообще в XXI веке может понадобиться использование функций printf() / fprintf() в коде на C++/Qt? Такая ситуация может возникнуть в случае, если заменяется стандартный хендлер отладочного вывода путем использования функции
qInstallMessageHandler( ourDebugPrintFunction )
Проблема в том, что внутри ourDebugPrintFunction() нельзя использовать потоковый вывод через qDebug(), qWarning() и прочие подобные инструменты, так как получится рекурсия. Поэтому для вывода в консоль надо использовать либо стандартные C++ потоки ввода/вывода (что медленно), либо стандартные функции вывода библиотеки iostream.
Ниже приведена простейшая реализация хендлера, в котором возникает проблема с задержкой появления сообщений в окне QtCreator:
void LogHelper::ourDebugPrintFunction(QtMsgType type,
const QMessageLogContext &context,
const QString &msgText)
{
Q_UNUSED(context)
switch (type) {
case QtDebugMsg:
// Отладочный вывод возможен только при компиляции в режиме отладки
#ifdef QT_DEBUG
smartPrintDebugMessage("[DBG] "+msgText+"\n");
#endif
break;
case QtWarningMsg:
smartPrintDebugMessage("[WRN] "+msgText+"\n");
break;
case QtCriticalMsg:
smartPrintDebugMessage("[CRERR] "+msgText+"\n");
break;
case QtFatalMsg:
smartPrintDebugMessage("[FTERR] "+msgText+"\n");
abort();
case QtInfoMsg:
smartPrintDebugMessage("[INF] "+msgText+"\n");
break;
}
}
void LogHelper::smartPrintDebugMessage(QString msg)
{
// Подготовка текста для вывода
QTime currTime = QTime::currentTime();
QString timeText = currTime.toString("hh:mm:ss.zzz");
msg=timeText+" "+msg;
// Быстрый вывод в консоль
printf("%s", qPrintable(msg));
}
void LogHelper::setDebugMessageHandler()
{
...
// Устанавливается Qt-обработчик консольного вывода
qInstallMessageHandler(ourDebugPrintFunction);
}
Проблема здесь в том, что "быстрый вывод в консоль" через printf(), в случае окна QtCreator, оказывается совсем не быстрым, а буферизированным.
Решается проблема следующим образом: вместо стандартного вывода надо использовать поток ошибок. Приложения Qt, при своем старте, по-умолчанию так настраивают консольный вывод, что поток ошибок stderr попадает в stdout без дополнительных перенаправлений потоков. А отправка сообщений в поток stderr самим QtCreator не буферезируется, и поэтому сообщения появляются без задержки.
В официальной документации об этой особенности внятно не сказано, зато в куске кода, который приводится в качестве примера, видно использование функции fprintf() с потоком stderr. Поэтому достаточно вместо строки с printf() написать следующую команду:
// Быстрый вывод в консоль
fprintf(stderr, "%s", qPrintable(msg));
... тогда все отладочные сообщения будут появляться в QtCreator без задержки. Примечательно, что если вместо stderr написать stdout, то вывод в окне QtCreator опять станет медленным.
В общем, при построении подсистемы вывода лога в консоль, надо учитывать вышеописанную особенность среды QtCreator.