zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Qt分析之调试跟踪系统

Qt调试系统 分析 跟踪
2023-09-14 09:05:26 时间

在我们前面的分析中,经常看到qWarning()和qDebug()之类的调用。今天深入的分析QT的调试跟踪系统。

我们先看QDebug.h中的宏定义:

#if !defined(QT_NO_DEBUG_STREAM)
Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }

#else // QT_NO_DEBUG_STREAM
#undef qDebug
inline QNoDebug qDebug() { return QNoDebug(); }
#define qDebug QT_NO_QDEBUG_MACRO

#ifdef QT_NO_MEMBER_TEMPLATES
template<typename T>
inline QNoDebug operator<<(QNoDebug debug, const T &) { return debug; }
#endif

#endif

#if !defined(QT_NO_WARNING_OUTPUT)
Q_CORE_EXPORT_INLINE QDebug qWarning() { return QDebug(QtWarningMsg); }
#else
#undef qWarning
inline QNoDebug qWarning() { return QNoDebug(); }
#define qWarning QT_NO_QWARNING_MACRO
#endif

这里很明显,QT的调试跟踪系统就是两条:DEBUG和WARNING。先看DEBUG,如果我们定义了宏QT_NO_DEBUG_STREAM,qDebug()被定义成QNoDebug(),而QT_NO_QDEBUG_MACRO的定义:

#define QT_NO_QDEBUG_MACRO if(1); else qDebug

注意if后面的分号,其等价于空语句。

我们再看QNoDebug类的定义:

class QNoDebug
{
public:
    inline QNoDebug(){}
    inline QNoDebug(const QDebug &){}
    inline ~QNoDebug(){}
#if !defined( QT_NO_TEXTSTREAM )
    inline QNoDebug &operator<<(QTextStreamFunction) { return *this; }
    inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; }
#endif
    inline QNoDebug &space() { return *this; }
    inline QNoDebug &nospace() { return *this; }
    inline QNoDebug &maybeSpace() { return *this; }

#ifndef QT_NO_MEMBER_TEMPLATES
    template<typename T>
    inline QNoDebug &operator<<(const T &) { return *this; }
#endif
};

重载的<<操作只是返回其自身。另外一种情况(就是有DEBUG_STREAM)的时候,也就是缺省情况下,qDebug被定为QDebug,QDebug的输出设备是什么呢?看QDebug类中构造的定义:

1     inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
2     inline QDebug(QString *string) : stream(new Stream(string)) {}
3     inline QDebug(QtMsgType t) : stream(new Stream(t)) {}
4     inline QDebug(const QDebug &o):stream(o.stream) { ++stream->ref; }

可以知道QDebug的输出设备可以使QString,QIODevice或者QtMsgType指定的类型。

如果我们在main()函数里面写这样一行程序:

qDebug() << "Hello world!";

其执行的效果是向stderr设备输出"Hello world!",根据

Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }

定义,实际调用的是:

inline QDebug(QtMsgType t) : stream(new Stream(t)) {}

语句,在新生成Stream对象的时候,调用的是:

Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t), space(true), message_output(true) {}

执行完毕之后,会释放QDebug对象,看看QDebug的释放:

inline ~QDebug() {
        if (!--stream->ref) {
            if(stream->message_output)
                qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
            delete stream;
        }
    }

我们再来看qt_message_output()的代码:

void qt_message_output(QtMsgType msgType, const char *buf)
{
    if (handler) {
        (*handler)(msgType, buf);
    } else {
#if defined(Q_CC_MWERKS)
        mac_default_handler(buf);
#elif defined(Q_OS_WINCE)
        QString fstr = QString::fromLatin1(buf);
        fstr += QLatin1String("\n");
        OutputDebugString(reinterpret_cast<const wchar_t *> (fstr.utf16()));
#else
        fprintf(stderr, "%s\n", buf);
        fflush(stderr);
#endif
    }

    if (msgType == QtFatalMsg
        || (msgType == QtWarningMsg
            && (!qgetenv("QT_FATAL_WARNINGS").isNull())) ) {

#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
        // get the current report mode
        int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
        _CrtSetReportMode(_CRT_ERROR, reportMode);
#if !defined(Q_OS_WINCE)
        int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, buf);
#else
        int ret = _CrtDbgReportW(_CRT_ERROR, _CRT_WIDE(__FILE__),
            __LINE__, _CRT_WIDE(QT_VERSION_STR), reinterpret_cast<const wchar_t *> (QString::fromLatin1(buf).utf16()));
#endif
        if (ret == 0  && reportMode & _CRTDBG_MODE_WNDW)
            return; // ignore
        else if (ret == 1)
            _CrtDbgBreak();
#endif

#if (defined(Q_OS_UNIX) || defined(Q_CC_MINGW))
        abort(); // trap; generates core dump
#else
        exit(1); // goodbye cruel world
#endif
    }
}

首先是判断用户有没有handler,如果有这个处理能力就让用户自己处理:

static QtMsgHandler handler = 0;                // pointer to debug handler

在Qglobal.cpp中定义。要是想自己处理,只要让handler指向自己的处理函数就可以了,多少有点C程序的味道。

否则的话就会输出到stderr设备上(Win系统中非WinCE的情况)。

其他,如果是FATAL(致命)错误或者警告,则会调用_CrtDbgReport(),其模式是_CRT_ERROR。也就是往调试器报告致命错误。QWarning的实现基本类似,不再深入一步一步分析。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS,OpenCV,Quick模块,面试题等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓