zoukankan      html  css  js  c++  java
  • QT分析之调试跟踪系统

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201002004518944/

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

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

     1 #if !defined(QT_NO_DEBUG_STREAM)
     2 Q_CORE_EXPORT_INLINE QDebug qDebug() { return QDebug(QtDebugMsg); }
     3 
     4 #else // QT_NO_DEBUG_STREAM
     5 #undef qDebug
     6 inline QNoDebug qDebug() { return QNoDebug(); }
     7 #define qDebug QT_NO_QDEBUG_MACRO
     8 
     9 #ifdef QT_NO_MEMBER_TEMPLATES
    10 template<typename T>
    11 inline QNoDebug operator<<(QNoDebug debug, const T &) { return debug; }
    12 #endif
    13 
    14 #endif
    15 
    16 #if !defined(QT_NO_WARNING_OUTPUT)
    17 Q_CORE_EXPORT_INLINE QDebug qWarning() { return QDebug(QtWarningMsg); }
    18 #else
    19 #undef qWarning
    20 inline QNoDebug qWarning() { return QNoDebug(); }
    21 #define qWarning QT_NO_QWARNING_MACRO
    22 #endif

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

    1 #define QT_NO_QDEBUG_MACRO if(1); else qDebug

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

    我们再看QNoDebug类的定义:

     1 class QNoDebug
     2 {
     3 public:
     4     inline QNoDebug(){}
     5     inline QNoDebug(const QDebug &){}
     6     inline ~QNoDebug(){}
     7 #if !defined( QT_NO_TEXTSTREAM )
     8     inline QNoDebug &operator<<(QTextStreamFunction) { return *this; }
     9     inline QNoDebug &operator<<(QTextStreamManipulator) { return *this; }
    10 #endif
    11     inline QNoDebug &space() { return *this; }
    12     inline QNoDebug &nospace() { return *this; }
    13     inline QNoDebug &maybeSpace() { return *this; }
    14 
    15 #ifndef QT_NO_MEMBER_TEMPLATES
    16     template<typename T>
    17     inline QNoDebug &operator<<(const T &) { return *this; }
    18 #endif
    19 };

    重载的<<操作只是返回其自身。另外一种情况(就是有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()函数里面写这样一行程序:

    1 qDebug() << "Hello world!";

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

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

    定义,实际调用的是:

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

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

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

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

    1 inline ~QDebug() {
    2         if (!--stream->ref) {
    3             if(stream->message_output)
    4                 qt_message_output(stream->type, stream->buffer.toLocal8Bit().data());
    5             delete stream;
    6         }
    7     }

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

     1 void qt_message_output(QtMsgType msgType, const char *buf)
     2 {
     3     if (handler) {
     4         (*handler)(msgType, buf);
     5     } else {
     6 #if defined(Q_CC_MWERKS)
     7         mac_default_handler(buf);
     8 #elif defined(Q_OS_WINCE)
     9         QString fstr = QString::fromLatin1(buf);
    10         fstr += QLatin1String("
    ");
    11         OutputDebugString(reinterpret_cast<const wchar_t *> (fstr.utf16()));
    12 #else
    13         fprintf(stderr, "%s
    ", buf);
    14         fflush(stderr);
    15 #endif
    16     }
    17 
    18     if (msgType == QtFatalMsg
    19         || (msgType == QtWarningMsg
    20             && (!qgetenv("QT_FATAL_WARNINGS").isNull())) ) {
    21 
    22 #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
    23         // get the current report mode
    24         int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
    25         _CrtSetReportMode(_CRT_ERROR, reportMode);
    26 #if !defined(Q_OS_WINCE)
    27         int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, buf);
    28 #else
    29         int ret = _CrtDbgReportW(_CRT_ERROR, _CRT_WIDE(__FILE__),
    30             __LINE__, _CRT_WIDE(QT_VERSION_STR), reinterpret_cast<const wchar_t *> (QString::fromLatin1(buf).utf16()));
    31 #endif
    32         if (ret == 0  && reportMode & _CRTDBG_MODE_WNDW)
    33             return; // ignore
    34         else if (ret == 1)
    35             _CrtDbgBreak();
    36 #endif
    37 
    38 #if (defined(Q_OS_UNIX) || defined(Q_CC_MINGW))
    39         abort(); // trap; generates core dump
    40 #else
    41         exit(1); // goodbye cruel world
    42 #endif
    43     }
    44 }

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

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

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

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

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

  • 相关阅读:
    ES6 函数——箭头函数
    ES6 变量var、let和const
    vue项目可视化管理之(vue ui)
    记录一次并发测试的bug
    python接口自动化读取json、yaml、ini文件
    python接口自动化学习笔记(封装方法用于读取excel)
    python 数据驱动(ddt,unpack)
    Python 做Django 项目遇到问题:Not Found: /c_hello(或/c_webskt/)
    下载安装破解PyCharm(转载)
    Selenium 八种元素定位方法
  • 原文地址:https://www.cnblogs.com/lfsblack/p/5279170.html
Copyright © 2011-2022 走看看