说明
- 在开发中需要一些调试手段来确认程序执行;在嵌入式开发工作中暂时未使用QTCreate,因此未使用QTCreate进行调试。
- 开发环境QT版本为4.7.4。
调试打印
- Qt框架采用C++语言实现,因此支持多种方式调试打印。
- C语言printf等函数。
- C++语言std::cout等接口。
- Qt 平台调试打印(qDebug、qWarnng、qCritical、qFatal)。
- 方式3是QT平台官方的打印方式,对QT平台兼容性好,std::cout 大部分情况下可以正常使用,但是有些情况下会出现兼容性问题,例如:
#include <QApplication>
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这些问题可能已解决,但由于不是官方方式,兼容性问题不可避免的。
- 方式3原生支持QT平台的基本数据类型,例如QString,QByteArray,QDate,QRectF,QVariantHash,QFont等等,其它方式需要特殊处理。
- 方式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 <QDebug>
- c++ 数据流式
QString str("123");
qDebug() << str << endl;
- 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 <QDebug>
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 <qapplication.h>
#include <stdio.h>
#include <stdlib.h>
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。