C++에는 컴파일 시점에 자동으로 치환되는 사전 정의 매크로(predefined macros)가 여러 개 존재합니다. 그중에서도 __FILE__, __LINE__, __FUNCTION__은 디버깅과 로깅(log) 작업에서 특히 유용하게 활용됩니다. 이번 글에서는 세 매크로의 역할과 실제 사용 예제를 살펴보겠습니다.
1. __FILE__ — 현재 파일 경로
__FILE__ 매크로는 현재 컴파일 중인 소스 파일의 전체 경로를 문자열 리터럴로 반환합니다. 로그 파일을 생성할 때 어떤 파일에서 오류가 발생했는지 기록해야 하는 경우에 매우 유용합니다.
예제 코드
#include <iostream>
using namespace std;
int errorLog(const char* file, const std::string& msg) {
cerr << "[" << file << "] " << msg << endl;
}
#define LOG(msg) errorLog(__FILE__, msg)
int main() {
LOG("This is a dummy error");
}실행 결과
[D:\Misc C and C++ Questions\test_prog.cpp] This is a dummy error
출력 결과에서 볼 수 있듯이, LOG 매크로가 호출된 소스 파일의 전체 경로가 함께 기록됩니다.
2. __LINE__ — 현재 줄 번호
__LINE__ 매크로는 해당 매크로가 사용된 소스 파일 내의 현재 줄 번호를 정수 값으로 반환합니다. 로그 메시지와 함께 줄 번호를 남기면, 수천 줄에 달하는 코드에서도 오류 발생 위치를 즉시 찾아낼 수 있습니다.
예제 코드
#include <iostream>
using namespace std;
int errorLog(int line, const std::string& msg) {
cerr << "[" << line << "] " << msg << endl;
}
#define LOG(msg) errorLog(__LINE__, msg)
int main() {
LOG("This is a dummy error");
}실행 결과
[12] This is a dummy error
이 예제에서는 LOG 매크로가 호출된 위치가 소스 코드의 12번째 줄임을 알려줍니다.
3. __FUNCTION__ — 현재 함수 이름
__FUNCTION__ 매크로는 해당 코드가 실행되는 현재 함수의 이름을 문자열로 반환합니다. 함수별로 로그를 구분해야 할 때 유용하며, 호출 흐름을 추적하는 트레이싱(trace) 코드 작성에도 널리 사용됩니다.
예제 코드
#include <iostream>
using namespace std;
int errorLog(const char* func, const std::string& msg) {
cerr << "[" << func << "] " << msg << endl;
}
#define LOG(msg) errorLog(__FUNCTION__, msg)
void TestFunction() {
LOG("Send from Function");
}
int main() {
TestFunction();
LOG("This is a dummy error");
}실행 결과
[TestFunction] Send from Function [main] This is a dummy error
각 로그 메시지 앞에 해당 매크로가 호출된 함수의 이름이 함께 출력되는 것을 확인할 수 있습니다.
참고 사항
세 매크로를 조합하면 파일명, 줄 번호, 함수 이름을 한 번에 남기는 강력한 로깅 매크로를 만들 수 있습니다.
#define LOG(msg) errorLog(__FILE__, __LINE__, __FUNCTION__, msg)
또한, __FUNCTION__은 컴파일러마다 지원 방식이 다를 수 있으므로 이식성(portability)이 중요한 프로젝트라면 C++11부터 표준으로 도입된 __func__를 사용하는 것이 좋습니다. __FILE__과 __LINE__은 C 및 C++ 표준에서 공식적으로 보장되는 매크로입니다.