调试技巧
我们在此介绍一些有用的提示,以帮助您调试基于 Qt 的软件。
为调试配置 Qt
在配置安装 Qt 时,可以确保在构建 Qt 时包含调试符号,这样可以更轻松地跟踪应用程序和库中的错误。不过,在某些平台上,以调试模式构建 Qt 会导致应用程序的大小超出预期。
在 macOS 和 Xcode 中调试
使用/不使用框架调试
您需要了解的有关调试库和框架的基本知识可在 developer.apple.com 中找到:Apple 技术说明 TN2124。
当你构建 Qt 时,默认情况下会构建框架,在框架内你会找到发布和调试版本(例如QtCore 和 QtCore_debug)。如果在联编 Qt 时传递-no-framework
标志,则会为每个 Qt 库联编两个 dylib(例如,libQtCore.4.dylib 和 libQtCore_debug.4.dylib)。
链接时会发生什么取决于是否使用框架。我们看不出有什么令人信服的理由推荐使用其中一种。
使用框架
由于发布库和调试库都在框架内,因此只需针对框架链接应用程序即可。然后,当你在调试器中运行时,你将得到发布版本或调试版本,这取决于你是否设置了DYLD_IMAGE_SUFFIX
。如果不设置,默认情况下得到的是发布版本(即非 _debug)。如果设置了DYLD_IMAGE_SUFFIX=_debug
,则会得到调试版本。
不带框架:
当您让qmake生成带有调试配置的 Makefile 时,它会与 _debug 版本的库链接,并为应用程序生成调试符号。然后,在 GDB 中运行此程序,就像在其他平台上运行 GDB 一样,你就可以在 Qt 内部进行跟踪了。
Qt 可识别的命令行选项
运行 Qt 应用程序时,可以指定几个有助于调试的命令行选项。QApplication 可识别这些选项。
选项 | 说明 |
---|---|
-nograb | 应用程序不应抓取the mouse 或the keyboard 。当程序在 Linux 下的gdb 调试器中运行时,默认设置为该选项。 |
-dograb | 忽略任何隐式或显式-nograb 。即使-nograb 在命令行中排在最后,-dograb 也会优先于-nograb 。 |
Qt 可识别的环境变量
运行时,Qt 应用程序会识别许多环境变量,其中一些变量对调试很有帮助:
变量 | 说明 |
---|---|
QT_DEBUG_PLUGINS | 设置为非零值可使 Qt 打印出它试图加载的每个 (C++) 插件的诊断信息。 |
QML_IMPORT_TRACE | 设置为非零值可使 QML 从导入加载机制中打印出诊断信息。 |
QT_HASH_SEED | 设置为整数值可禁用QHash 和QSet ,每次运行应用程序时使用新的随机排序,这在某些情况下可能会给测试和调试带来困难。 |
QT_WIN_DEBUG_CONSOLE | 在 Windows 中,GUI 应用程序不连接控制台,因此写入stdout 和stderr 的输出对用户来说是不可见的。集成开发环境通常会重定向并显示输出,但从命令行运行应用程序时,调试输出会丢失。要访问输出,可将此环境变量设置为new ,使应用程序分配一个新的控制台,或设置为attach ,使应用程序尝试附加到父进程的控制台。 |
警告和调试信息
Qt 包含用于写出警告和调试文本的全局 C++ 宏。普通宏使用默认的logging category ;分类日志宏允许您指定类别。您可以将它们用于以下目的:
普通宏 | 分类宏 | 目的 |
---|---|---|
qDebug() | qCDebug() | 用于编写自定义调试输出 |
qInfo() | qCInfo() | 用于输入信息 |
qWarning() | qCWarning() | 用于报告应用程序或库中的警告和可恢复错误 |
qCritical() | qCCritical() | 用于编写关键错误信息和报告系统错误 |
qFatal() | - | 用于在退出前写入致命错误信息 |
如果包含 <QtDebug> 头文件,qDebug()
宏也可用作输出流。例如
qDebug() << "Widget" << widget << "at position" << widget->pos();
在 Unix/X11 和 macOS 下,这些宏的 Qt 实现会打印到stderr
输出。在 Windows 下,如果是控制台应用程序,文本将发送到控制台;否则,将发送到调试器。
默认情况下,只打印消息。通过设置QT_MESSAGE_PATTERN
环境变量,可以包含更多信息。例如
QT_MESSAGE_PATTERN="[%{time process} %{type}] %{appname} %{category} %{function} - %{message}"
格式记录在qSetMessagePattern() 中。您也可以使用qInstallMessageHandler() 安装自己的消息处理程序。
如果设置了QT_FATAL_WARNINGS
环境变量,qWarning() 会在打印警告信息后退出。这样就可以很容易地在调试器中获得回溯信息。
qDebug()、qInfo() 和qWarning() 是调试工具。在编译过程中,可以通过定义QT_NO_DEBUG_OUTPUT
、QT_NO_INFO_OUTPUT
或QT_NO_WARNING_OUTPUT
来编译它们。
当应用程序出现异常外观或行为时,调试函数QObject::dumpObjectTree() 和QObject::dumpObjectInfo() 通常很有用。如果使用object names 则比不使用更有用,但即使没有名称也经常有用。
在 QML 中,dumpItemTree() 也有同样的作用。
为 qDebug() 流操作符提供支持
你可以实现qDebug() 使用的流操作符,为你的类提供调试支持。实现流运算符的类是QDebug
。使用QDebugStateSaver
可临时保存流的格式化选项。使用nospace() 和QTextStream manipulators 可进一步自定义格式。
下面是一个表示 2D 坐标的类的示例。
QDebug operator<<(QDebug dbg, const Coordinate &c) { QDebugStateSaver saver(dbg); dbg.nospace() << "(" << c.x() << ", " << c.y() << ")"; return dbg; }
创建自定义 Qt 类型》(Creating Custom Qt Types)文档将更深入地介绍自定义类型与Qt元对象系统的集成。
调试宏
头文件<QtGlobal>
包含一些调试宏和#define
s。
三个重要的宏是
- Q_ASSERT(cond),其中
cond
是布尔表达式,写入警告 "ASSERT:'cond' in file xyz.cpp, line 234",如果cond
为 false 则退出。 - Q_ASSERT_X(cond,where,what),其中
cond
是布尔表达式,where
是位置,what
是信息,写入警告:"ASSERT failure inwhere
: 'what
', file xyz.cpp, line 234" 如果cond
为 false,则退出。 - Q_CHECK_PTR(ptr),其中
ptr
是指针。写入警告 "在文件 xyz.cpp 第 234 行:超出内存 "的警告,如果ptr
为 0 则退出。
这些宏对于检测程序错误非常有用,例如像这样
char *alloc(int size) { Q_ASSERT(size > 0); char *ptr = new char[size]; Q_CHECK_PTR(ptr); return ptr; }
Q_ASSERT()、Q_ASSERT_X() 和Q_CHECK_PTR() 在编译过程中如果定义了QT_NO_DEBUG
,则扩展为无。因此,这些宏的参数不应产生任何副作用。下面是Q_CHECK_PTR() 的一个错误用法:
char *alloc(int size) { char *ptr; Q_CHECK_PTR(ptr = new char[size]); // WRONG return ptr; }
如果这段代码在编译时定义了QT_NO_DEBUG
,那么Q_CHECK_PTR() 表达式中的代码将不会被执行,alloc将返回一个未初始化的指针。
Qt 库包含数以百计的内部检查,当检测到编程错误时会打印警告信息。因此,我们建议您在开发基于 Qt 的软件时使用调试版本的 Qt。
QML 中也可以记录日志和categorized logging 。
常见错误
有一个非常常见的错误值得在此一提:如果您在类声明中包含Q_OBJECT 宏,并运行Meta-Object Compiler(moc
),但忘记将moc
生成的对象代码链接到可执行文件中,您将得到非常混乱的错误信息。任何抱怨缺少vtbl
,_vtbl
,__vtbl
或类似内容的链接错误都可能是这个问题造成的。
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.