Identifier ทั้งสามใช้สำหรับดึงข้อมูลฟังก์ชันปัจจุบัน แตกต่างกันในระดับรายละเอียดและ Standard Compliance
ตารางเปรียบเทียบ
| Identifier | Standard | เนื้อหา | ตัวอย่าง Output |
|---|---|---|---|
__func__ | C99, C++11 | Function Name เท่านั้น | "main", "foo" |
__FUNCTION__ | GNU Extension (C/C++) | เหมือน __func__ | "main" |
__PRETTY_FUNCTION__ | GNU Extension (GCC/Clang) | Pretty Signature (Class, Template, Const, Ref, Params) | "void MyClass::method() const" |
__FUNCSIG__ | MSVC Extension | Pretty Signature (MSVC Format) | "void __cdecl MyClass::method(void) const" |
ตัวอย่างเปรียบเทียบ
#include <iostream>
class MyClass {
public:
void method() const {
std::cout << "__PRETTY_FUNCTION__: " << __PRETTY_FUNCTION__ << '\n';
std::cout << "__func__: " << __func__ << '\n';
}
};
template <typename T>
void templateFunc(T) {
std::cout << "__PRETTY_FUNCTION__: " << __PRETTY_FUNCTION__ << '\n';
}
int main() {
std::cout << "__FUNCTION__: " << __FUNCTION__ << '\n';
MyClass().method();
templateFunc(42);
}
ผลลัพธ์ (GCC/Clang)
__FUNCTION__: main
__PRETTY_FUNCTION__: void MyClass::method() const
__func__: method
__PRETTY_FUNCTION__: void templateFunc(T) [with T = int]
การประยุกต์: Portable Logging Macro
// Cross-Compiler Function Name Macro
#if defined(__GNUC__) || defined(__clang__)
#define FUNC_NAME __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define FUNC_NAME __FUNCSIG__
#else
#define FUNC_NAME __func__
#endif
#define LOG(msg) std::cerr << "[" << FUNC_NAME << "] " << msg << '\n'
void process() {
LOG("Start processing");
// ...
LOG("End processing");
}
ใน Lambda Expressions
auto lambda = []() {
std::cout << __func__ << '\n'; // GCC: "", MSVC: "operator()"
};
ข้อจำกัด
- ไม่ใช่ Preprocessor Macro -> ไม่ทำงานใน
#if __func__เป็น `static const char[]` Local Variable- C++ Standard ไม่รวม
__PRETTY_FUNCTION__(Vendor Extension)
สรุป
- Portable Code: ใช้
__func__(C++11 Standard) - Debug/Log Detailed Signature: ใช้
__PRETTY_FUNCTION__(GCC/Clang) หรือ__FUNCSIG__(MSVC) - สร้าง Portable Macro ด้วย
#ifdefตรวจสอบ Compiler