Debugging-Techniken

Hier finden Sie einige nützliche Hinweise, die Ihnen beim Debuggen Ihrer Qt-basierten Software helfen.

Qt für die Fehlersuche konfigurieren

Wenn Sie Qt für die Installation konfigurieren, können Sie sicherstellen, dass es Debugsymbole enthält, die das Aufspüren von Fehlern in Anwendungen und Bibliotheken erleichtern können. Auf einigen Plattformen führt die Erstellung von Qt im Debug-Modus jedoch dazu, dass die Anwendungen größer werden als erwünscht.

Fehlersuche in macOS und Xcode

Debuggen mit/ohne Frameworks

Die grundlegenden Dinge, die Sie über Debug-Bibliotheken und Frameworks wissen müssen, finden Sie unter developer.apple.com in: Apple Technical Note TN2124.

Wenn Sie Qt bauen, werden standardmäßig Frameworks gebaut, und innerhalb des Frameworks finden Sie sowohl eine Release- als auch eine Debug-Version (z.B. QtCore und QtCore_debug). Wenn Sie beim Erstellen von Qt das Flag -no-framework angeben, werden für jede Qt-Bibliothek zwei Dylibs erstellt (z. B. libQtCore.4.dylib und libQtCore_debug.4.dylib).

Was beim Linken passiert, hängt davon ab, ob Sie Frameworks verwenden oder nicht. Wir sehen keinen zwingenden Grund, das eine dem anderen vorzuziehen.

Mit Frameworks:

Da sich die Release- und Debug-Bibliotheken innerhalb des Frameworks befinden, wird die Anwendung einfach gegen das Framework gelinkt. Wenn Sie sie dann im Debugger ausführen, erhalten Sie entweder die Release- oder die Debug-Version, je nachdem, ob Sie DYLD_IMAGE_SUFFIX gesetzt haben. Wenn Sie dies nicht tun, erhalten Sie standardmäßig die Release-Version (d. h. nicht _debug). Wenn Sie DYLD_IMAGE_SUFFIX=_debug setzen, erhalten Sie die Debug-Version.

Ohne Frameworks:

Wenn Sie qmake anweisen, ein Makefile mit der Debug-Konfiguration zu erzeugen, wird es gegen die _debug-Version der Bibliotheken linken und Debug-Symbole für die Anwendung erzeugen. Das Ausführen dieses Programms in GDB funktioniert dann wie das Ausführen von GDB auf anderen Plattformen, und Sie sind in der Lage, innerhalb von Qt zu tracen.

Kommandozeilenoptionen, die von Qt erkannt werden

Wenn Sie eine Qt-Anwendung ausführen, können Sie verschiedene Kommandozeilenoptionen angeben, die beim Debuggen helfen können. Diese werden von QApplication erkannt.

OptionBeschreibung
-nograbDie Anwendung sollte niemals the mouse oder the keyboard greifen. Diese Option ist standardmäßig gesetzt, wenn das Programm im gdb Debugger unter Linux ausgeführt wird.
-dograbIgnorieren Sie alle impliziten oder expliziten -nograb. -dograb hat Vorrang vor -nograb, auch wenn -nograb als letztes in der Kommandozeile steht.

Umgebungsvariablen, die von Qt erkannt werden

Zur Laufzeit erkennt eine Qt-Anwendung viele Umgebungsvariablen, von denen einige für die Fehlersuche hilfreich sein können:

VariableBeschreibung
QT_DEBUG_PLUGINSAuf einen Wert ungleich Null gesetzt, damit Qt Diagnoseinformationen über jedes (C++) Plugin ausgibt, das es zu laden versucht.
QML_IMPORT_TRACESetzen Sie diesen Wert auf einen Wert ungleich Null, damit QML Diagnoseinformationen über den Import-Lademechanismus ausgibt.
QT_HASH_SEEDSetzen Sie diesen Wert auf eine ganze Zahl, um QHash und QSet zu deaktivieren und eine neue zufällige Reihenfolge für jeden Anwendungslauf zu verwenden, was in einigen Fällen das Testen und Debuggen erschweren kann.
QT_WIN_DEBUG_CONSOLEUnter Windows sind GUI-Anwendungen nicht mit einer Konsole verbunden, so dass Ausgaben, die an stdout und stderr geschrieben werden, für den Benutzer nicht sichtbar sind. IDEs leiten die Ausgabe normalerweise um und zeigen sie an, aber wenn eine Anwendung von der Befehlszeile aus ausgeführt wird, geht die Debug-Ausgabe verloren. Um Zugriff auf die Ausgabe zu erhalten, setzen Sie diese Umgebungsvariable auf new, damit die Anwendung eine neue Konsole zuweist, oder auf attach, damit die Anwendung versucht, sich an die Konsole des Elternprozesses anzuhängen.

Warn- und Debugging-Meldungen

Qt enthält globale C++-Makros für die Ausgabe von Warn- und Fehlersuchtexten. Die einfachen Makros verwenden eine Standardvorgabe logging category; die kategorisierten Logging-Makros erlauben es Ihnen, die Kategorie anzugeben. Sie können sie für die folgenden Zwecke verwenden:

Einfaches MakroKategorisiertes MakroZweck
qDebug()qCDebug()Wird zum Schreiben von benutzerdefinierten Debug-Ausgaben verwendet
qInfo()qCInfo()Wird für Informationsmeldungen verwendet
qWarning()qCWarning()Wird verwendet, um Warnungen und behebbare Fehler in Ihrer Anwendung oder Bibliothek zu melden
qCritical()qCCritical()Wird verwendet, um kritische Fehlermeldungen zu schreiben und Systemfehler zu melden
qFatal()-Wird für das Schreiben von Meldungen über fatale Fehler kurz vor dem Beenden verwendet

Wenn Sie die <QtDebug>-Header-Datei einschließen, kann das qDebug() -Makro auch als Ausgabestrom verwendet werden. Ein Beispiel:

qDebug() << "Widget" << widget << "at position" << widget->pos();

Die Qt-Implementierung dieser Makros gibt unter Unix/X11 und macOS auf die Ausgabe stderr aus. Unter Windows wird der Text an die Konsole gesendet, wenn es sich um eine Konsolenanwendung handelt; andernfalls wird er an den Debugger gesendet.

Standardmäßig wird nur die Nachricht gedruckt. Sie können zusätzliche Informationen einfügen, indem Sie die Umgebungsvariable QT_MESSAGE_PATTERN setzen. Ein Beispiel:

QT_MESSAGE_PATTERN="[%{time process} %{type}] %{appname} %{category} %{function} - %{message}"

Das Format ist in qSetMessagePattern() dokumentiert. Sie können auch Ihren eigenen Message-Handler mit qInstallMessageHandler() installieren.

Wenn die Umgebungsvariable QT_FATAL_WARNINGS gesetzt ist, wird qWarning() nach der Ausgabe der Warnmeldung beendet. Dies macht es einfach, eine Rückverfolgung im Debugger zu erhalten.

qDebug(), qInfo(), und qWarning() sind Debugging-Werkzeuge. Sie können wegkompiliert werden, indem QT_NO_DEBUG_OUTPUT, QT_NO_INFO_OUTPUT oder QT_NO_WARNING_OUTPUT während der Kompilierung definiert werden.

Die Debugging-Funktionen QObject::dumpObjectTree() und QObject::dumpObjectInfo() sind oft nützlich, wenn eine Anwendung seltsam aussieht oder sich seltsam verhält. Sie sind nützlicher, wenn Sie object names verwenden, als wenn Sie sie nicht verwenden, aber oft auch ohne Namen nützlich.

In QML dient dumpItemTree() demselben Zweck.

Unterstützung für den qDebug() Stream-Operator

Sie können den von qDebug() verwendeten Stream-Operator implementieren, um Debugging-Unterstützung für Ihre Klassen bereitzustellen. Die Klasse, die den Stream implementiert, ist QDebug. Verwenden Sie QDebugStateSaver, um die Formatierungsoptionen des Streams vorübergehend zu speichern. Verwenden Sie nospace() und QTextStream manipulators, um die Formatierung weiter anzupassen.

Hier ist ein Beispiel für eine Klasse, die eine 2D-Koordinate darstellt.

QDebug operator<<(QDebug dbg, const Coordinate &c)
{
    QDebugStateSaver saver(dbg);
    dbg.nospace() << "(" << c.x() << ", " << c.y() << ")";

    return dbg;
}

Die Integration von benutzerdefinierten Typen in das Meta-Objektsystem von Qt wird im Dokument Erstellen von benutzerdefinierten Qt-Typen ausführlicher behandelt.

Debugging-Makros

Die Header-Datei <QtGlobal> enthält einige Debugging-Makros und #defines.

Drei wichtige Makros sind:

  • Q_ASSERT(cond), wobei cond ein boolescher Ausdruck ist, schreibt die Warnung "ASSERT:'cond' in Datei xyz.cpp, Zeile 234" und beendet sich, wenn cond falsch ist.
  • Q_ASSERT_X(cond, where, what), wobei cond ein boolescher Ausdruck, where ein Ort und what eine Nachricht ist, schreibt die Warnung: "ASSERT-Fehler in where: 'what', Datei xyz.cpp, Zeile 234" und beendet sich, wenn cond falsch ist.
  • Q_CHECK_PTR(ptr), wobei ptr ein Zeiger ist. Schreibt die Warnung "In Datei xyz.cpp, Zeile 234: Out of memory" und beendet sich, wenn ptr gleich 0 ist.

Diese Makros sind nützlich, um Programmfehler zu erkennen, z.B. wie folgt:

char *alloc(int size)
{
    Q_ASSERT(size > 0);
    char *ptr = new char[size];
    Q_CHECK_PTR(ptr);
    return ptr;
}

Q_ASSERT(), Q_ASSERT_X() und Q_CHECK_PTR() expandieren zu nichts, wenn QT_NO_DEBUG während der Kompilierung definiert wird. Aus diesem Grund sollten die Argumente für diese Makros keine Nebeneffekte haben. Hier ist eine falsche Verwendung von Q_CHECK_PTR():

char *alloc(int size)
{
    char *ptr;
    Q_CHECK_PTR(ptr = new char[size]);  // WRONG
    return ptr;
}

Wenn dieser Code kompiliert wird, während QT_NO_DEBUG definiert ist, wird der Code im Ausdruck Q_CHECK_PTR() nicht ausgeführt und alloc gibt einen nicht initialisierten Zeiger zurück.

Die Qt-Bibliothek enthält Hunderte von internen Prüfungen, die Warnmeldungen ausgeben, wenn ein Programmierfehler entdeckt wird. Wir empfehlen daher, dass Sie eine Debug-Version von Qt verwenden, wenn Sie Qt-basierte Software entwickeln.

Logging und categorized logging sind auch in QML möglich.

Häufige Bugs

Es gibt einen Fehler, der so häufig auftritt, dass er hier erwähnt werden sollte: Wenn Sie das Makro Q_OBJECT in eine Klassendeklaration einbinden und den Meta-Object Compiler (moc) ausführen, aber vergessen, den moc-generierten Objektcode in Ihr Executable zu linken, erhalten Sie sehr verwirrende Fehlermeldungen. Jeder Link-Fehler, der sich über das Fehlen von vtbl, _vtbl, __vtbl oder ähnlichem beschwert, ist wahrscheinlich ein Ergebnis dieses Problems.

© 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.