调试方式

说明

  • 在开发中需要一些调试手段来确认程序执行;嵌入式开发暂未使用QTCreate,因此未研究QTCreate工具的使用。
  • 开发环境QT版本为4.7.4。

调试打印

  • Qt框架采用C++语言实现,因此支持多种方式调试打印。
  1. C语言printf等函数。
  2. C++语言std::cout等接口。
  3. Qt 平台调试打印(qDebug、qWarnng、qCritical、qFatal)。
  • 方式区别
  1. 方式3是QT平台官方的打印方式,对QT平台兼容性好,std::cout 大部分情况下可以正常使用,但是有些情况下会出现兼容性问题,例如:
#include 

using namespace std;
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    
    cout << "test" << endl;
    return a.exec();
}
* 以上代码不能正常输出,原因是和QTextStream的cout、cin冲突了,不能使用using namespace std,去掉后 改为std::cout就行了。
* 新版本QT这些问题可能已解决,但由于不是官方方式,兼容性问题不可避免的。
  1. 方式3原生支持QT平台的基本数据类型,例如QString,QByteArray,QDate,QRectF,QVariantHash,QFont等等,其它方式需要特殊处理。
  2. 方式3是在std::cout基础上实现的,性能较低,网上有很多三种方式的性能对比,性能表现:printf > std::cout > qDebug,qDebug相对于std::cout和printf差距过大(6~10倍)。
  • 综上所述,QT开发中尽量使用官方的打印方式,如有必要也可使用其它方式,但是需要注意使用方式。

Qt平台调试打印

日志等级分类

  • qDebug : 调试信息提示
  • qInfo: 一般的信息
  • qWarning: 一般的警告提示
  • qCritical: 严重错误提示
  • qFatal: 致命错误提示

打印等级限制

  • 暂未发现打印等级设置接口,但是我们可以通过打印等级的关闭宏 :QT_NO_DEBUG_OUTPUT,QT_NO_INFO_OUTPUT 和 QT_NO_WARNING_OUTPUT,实现打印的打开与关闭,以实现简单的打印等级限制。

按模块打印

  • 暂时未发现模块划分方法。

qDebug 使用

  • qInfo, qWarning,qCritical,qFatal 类似。

基本使用

  • 头文件
#include 
  1. c++ 数据流式
QString str("123");

qDebug() << str << endl;
  1. c 函数式
int year=18;
qDebug("My age is %d",year);

%a,%A 读入一个浮点值(仅C99有效)  
%c 读入一个字符   
%d 读入十进制整数  
%i 读入十进制,八进制,十六进制整数  
%o 读入八进制整数   
%x,%X 读入十六进制整数   
%s 读入一个字符串,遇空格、制表符或换行符结束。   
%f,%F,%e,%E,%g,%G 用来输入实数,可以用小数形式或指数形式输入。   
%p 读入一个指针   
%u 读入一个无符号十进制整数   
%n 至此已读入值的等价字符数   
%[] 扫描字符集合   
%% 读%符号
  • 一般会使用C++流方式,因为使用函数式的话很多内置对象,打印不知道该使用什么格式,如下:
QString name("LiLy");
qDebug("My name is %s", name); //编译报错

为自定义类型添加qDebug支持

  • 例子:
#include 
class Student
{
public:
    Student(const QString& nm){name = nm;}
    QString getName() const{return name;}
private:
    QString name;
};
QDebug operator<<(QDebug debug, const Student &c)
{
    debug << c.getName();
    return debug;
}
int main(int argc, char *argv[])
{
    Student student("John");
    qDebug() << student;
}

关闭qDebug打印

  • 一键关闭所有打印,只需要在pro文件里加上一行预定义宏。
DEFINES += QT_NO_DEBUG_OUTPUT
  • 缺陷:qDebug 只能关闭所有,不能按模块关闭,不方便进行单元测试。

中间处理

  • Qt提供了qInstallMsgHandler 方法用来定制消息发生后如何来处理。
  • qInstallMsgHandler 是一个回调函数,由qDebug、qWarnng、qCritical、qFatal这些函数进行触发,这样就允许用户自己来处理这些消息文本,例如:将这些消息文本输出并保存到相关的日志文件中。
  • 例子:
#include 
#include 
#include 

void customMessageHandler(QtMsgType type, const char *msg)
{
    QString txtMessage;
  
    switch (type) 
    {    
        case QtDebugMsg:    //调试信息提示
            txtMessage = QString("Debug: %1").arg(msg);
            break;

        case QtWarningMsg:    //一般的warning提示
            txtMessage = QString("Warning: %1").arg(msg);
            break;

        case QtCriticalMsg:    //严重错误提示
            txtMessage = QString("Critical: %1").arg(msg);
            break;

        case QtFatalMsg:    //致命错误提示
            txtMessage = QString("Fatal: %1").arg(msg);
            abort();
    }

    //保存输出相关信息到指定文件
    QFile outputFile("customMessageLog.txt");
    outputFile.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream textStream(&outputFile);
    textStream << txtMessage << endl;
}

int main( int argc, char * argv[] )   
{
    QApplication app( argc, argv );

    qInstallMsgHandler(customMessageHandler); //注册MsgHandler回调函数

    //以后就可以像下面这样直接打日志到文件中,而且日志也会包含时间信息
    qDebug("This is a debug message");
    qWarning("This is a warning message");
    qCritical("This is a critical message");
    qFatal("This is a fatal message");

    return app.exec();
}
  • 取消信息处理,直接调用qInstallMsgHandler(0)就可以。

  • 大部分调试宏定义于头文件 。

断言

  • QT中的断言和C或C++的类似。
  • Qt中提供了两个断言的宏Q_ASSERT()和Q_ASSERT_X()。
  • 定义
1. Q_ASSERT(bool)
2. Q_ASSERT_X(bool, device, log)  
  • 原理:断言判断bool值,为假的时候通过 qFatal() 函数输出错误信息。
  • 区别:Q_ASSERT_X 可以自定义log信息和设备信息; Q_ASSERT则打印Qt自带的log信息
  • 开启/关闭:默认开启,关闭需要定义宏QT_NO_DEBUG。

指针检查

  • 在C/C++开发中,经常会出现空指针而导致崩溃问题发生,如果没有使用调试手段,出现问题后很难定位到具体的代码行,使用断言或一些宏可以解决这个问题,QT平台有专门的宏,如下:
Q_CHECK_PTR 
  • 出现空指针导致的崩溃问题,会在崩溃前打印出问题代码信息,包括文件名,代码行等。
  • 开启/关闭:默认开启,关闭需要定义宏QT_NO_DEBUG。

你可能感兴趣的:(GUI,-,QT编程,qt)