디버깅 기법
여기서는 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을 생성하도록 지시하면, qmake는 라이브러리의 _debug 버전에 링크하고 앱에 대한 디버그 심볼을 생성합니다. 이렇게 생성된 프로그램을 GDB에서 실행하면 다른 플랫폼에서 GDB를 실행하는 것과 동일하게 작동하며, Qt 내부에서 추적이 가능해집니다.
Qt에서 인식하는 명령줄 옵션
Qt 애플리케이션을 실행할 때 디버깅에 도움이 되는 여러 명령줄 옵션을 지정할 수 있습니다. 이러한 옵션은 ` QApplication`에 의해 인식됩니다.
| 옵션 | 설명 |
|---|---|
-nograb | 애플리케이션이 the mouse 또는 the keyboard 을 절대 가로채지 않아야 합니다. 이 옵션은 Linux 환경에서 gdb 디버거에서 프로그램을 실행할 때 기본적으로 설정됩니다. |
-dograb | 명시적이든 묵시적이든 모든 -nograb 을 무시합니다. -dograb 은 명령줄의 마지막에 -nograb 이 있더라도 -nograb 보다 우선합니다. |
Qt에서 인식하는 환경 변수
실행 시 Qt 애플리케이션은 여러 환경 변수를 인식하며, 그중 일부는 디버깅에 도움이 될 수 있습니다:
| 변수 | 설명 |
|---|---|
QT_DEBUG_PLUGINS | 0이 아닌 값으로 설정하면 Qt가 로드하려는 각 (C++) 플러그인에 대한 진단 정보를 출력합니다. |
QML_IMPORT_TRACE | 0이 아닌 값으로 설정하면 QML이 임포트 로딩 메커니즘에 대한 진단 정보를 출력합니다. |
QT_HASH_SEED | 정수 값으로 설정하면 애플리케이션 실행 시마다 새로운 무작위 순서를 사용하여 QHash 및 QSet 를 비활성화합니다. 이로 인해 경우에 따라 테스트 및 디버깅이 어려워질 수 있습니다. |
QT_WIN_DEBUG_CONSOLE | Windows에서는 GUI 애플리케이션이 콘솔에 연결되지 않으므로, stdout 및 stderr 에 기록된 출력은 사용자에게 표시되지 않습니다. IDE는 일반적으로 출력을 리디렉션하여 표시하지만, 명령줄에서 애플리케이션을 실행할 경우 디버그 출력이 손실됩니다. 출력을 확인하려면 이 환경 변수를 ` 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/Linux 및 macOS 환경에서 Qt XML의 이러한 매크로 구현은 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 를 사용하여 서식을 추가로 사용자 정의할 수 있습니다.
다음은 2차원 좌표를 나타내는 클래스의 예시입니다.
QDebug operator<<(QDebug dbg, const Coordinate &c)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "(" << c.x() << ", " << c.y() << ")";
return dbg;
}사용자 정의 유형과 Qt의 메타 객체 시스템의 통합에 대해서는 ‘사용자 정의 Qt 유형 만들기 ’ 문서에서 더 자세히 다루고 있습니다.
디버깅 매크로
<QtGlobal> 헤더 파일에는 몇 가지 디버깅 매크로와 #define가 포함되어 있습니다.
세 가지 중요한 매크로는 다음과 같습니다.
- Q_ASSERT(cond)는
cond가 부울 표현식인 경우, “ASSERT:'cond' in file xyz.cpp, line 234”라는 경고를 출력하고,cond가 false인 경우 프로그램을 종료합니다. - Q_ASSERT_X(cond, where, what): 여기서
cond는 부울 표현식,where는 위치,what는 메시지이며,cond가 false인 경우 "where에서 ASSERT 실패: 'what', 파일 xyz.cpp, 234행"이라는 경고를 출력하고 프로그램을 종료합니다. - Q_CHECK_PTR(ptr), 여기서
ptr는 포인터입니다.ptr가 0인 경우 "파일 xyz.cpp, 234행: 메모리 부족"이라는 경고 메시지를 출력하고 프로그램을 종료합니다.
이러한 매크로는 프로그램 오류를 감지하는 데 유용합니다. 예를 들어 다음과 같이 사용할 수 있습니다:
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 또는 이와 유사한 파일이 없다는 링크 오류는 대부분 이 문제로 인해 발생하는 것입니다.
© 2026 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.