C와 C++에서는 디버깅이나 로깅 작업 시 현재 실행 중인 함수의 이름을 손쉽게 확인할 수 있도록 특수한 식별자들을 제공합니다. 이번 글에서는 __FUNCTION__, __func__, __PRETTY_FUNCTION__ 세 가지의 차이점과 각각의 용도를 자세히 살펴보겠습니다.
세 가지 식별자의 기본 개념
__FUNCTION__과 __func__는 사실상 동일한 역할을 합니다. 둘 다 현재 함수의 이름만을 문자열로 반환하며, 일부 구버전의 C 및 C++ 컴파일러에서는 __func__를 지원했습니다. __func__는 C99 표준부터 공식적으로 도입된 식별자이고, __FUNCTION__은 GCC 등에서 제공하는 비표준 확장 기능입니다.
반면 __PRETTY_FUNCTION__은 GCC(G++)에서 제공하는 확장 기능으로, 단순한 함수 이름 그 이상의 상세한 정보를 반환합니다. 이 매크로를 사용하면 함수의 이름뿐만 아니라 해당 함수가 어느 클래스에 속하는지, 반환 타입은 무엇인지, 매개변수 목록까지 함께 확인할 수 있습니다.
- __func__: 현재 함수 이름만 반환 (C99 표준)
- __FUNCTION__: 현재 함수 이름만 반환 (GCC 확장, __func__와 동일)
- __PRETTY_FUNCTION__: 반환 타입, 클래스 이름, 함수 이름, 매개변수까지 상세히 반환 (GCC 확장)
예제 코드
아래 예제를 통해 세 식별자가 실제로 어떤 값을 출력하는지 확인해 보겠습니다.
#include<iostream>
using namespace std;
class MyClass {
public:
void Class_Function() {
cout << "The result of __PRETTY_FUNCTION__: " << __PRETTY_FUNCTION__ << endl;
}
};
void TestFunction() {
cout << "Output of __func__ is: " << __func__ << endl;
}
main() {
cout << "Output of __FUNCTION__ is: " << __FUNCTION__ << endl;
TestFunction();
MyClass myObj;
myObj.Class_Function();
}
실행 결과
Output of __FUNCTION__ is: main Output of __func__ is: TestFunction The result of __PRETTY_FUNCTION__: void MyClass::Class_Function()
결과 분석
main 함수 내부에서 __FUNCTION__을 출력하면 단순히 main이라는 함수 이름만 표시됩니다. 마찬가지로 TestFunction 내부에서 __func__를 사용하면 TestFunction만 출력됩니다.
하지만 클래스의 멤버 함수인 Class_Function에서 __PRETTY_FUNCTION__을 사용하면 void MyClass::Class_Function()처럼 반환 타입(void), 소속 클래스(MyClass), 함수 이름, 매개변수 목록이 모두 포함된 전체 시그니처가 출력되는 것을 볼 수 있습니다.
정리 및 활용 팁
| 식별자 | 표준 여부 | 출력 내용 |
|---|---|---|
| __func__ | C99 / C++11 표준 | 함수 이름 |
| __FUNCTION__ | GCC 확장 (비표준) | 함수 이름 (__func__와 동일) |
| __PRETTY_FUNCTION__ | GCC 확장 (비표준) | 반환 타입 + 클래스명 + 함수 시그니처 전체 |
간단한 로깅에는 __func__나 __FUNCTION__으로 충분하지만, 클래스 구조가 복잡한 대규모 프로젝트에서는 __PRETTY_FUNCTION__을 활용하면 어느 클래스의 어떤 메서드에서 문제가 발생했는지 훨씬 빠르게 파악할 수 있습니다. 다만 후자 두 식별자는 GCC 계열 컴파일러 전용 확장이므로, MSVC 같은 다른 컴파일러에서는 지원 여부를 반드시 확인해야 합니다.