2013-03-08 65 views
13

我正在嘗試構建一個調試日誌消息函數,該函數記錄日誌消息從何處被調用的文件,行和函數。函數名稱的預定義宏__func__

#define DEBUG_PANIC(p) CLogging::Debuglogf("Debug marker (%s) - ::%s() in file: %s(%d)", p, __func__ , __FILE__, __LINE__); 

上面的代碼適用於一些編譯器,但不是全部。我的代碼需要與GCC以及Microsoft Visual Studio交叉兼容。我已經添加了下面的定義來幫助兼容性。

#ifndef __FUNCTION_NAME__ 
    #if defined __func__ 
     // Undeclared 
     #define __FUNCTION_NAME__ __func__ 
    #elif defined __FUNCTION__ 
     // Undeclared 
     #define __FUNCTION_NAME__ __FUNCTION__ 
    #elif defined __PRETTY_FUNCTION__ 
     // Undeclared 
     #define __FUNCTION_NAME__ __PRETTY_FUNCTION__ 
    #else 
     // Declared 
     #define __FUNCTION_NAME__ "N/A" 
    #endif // __func__ 

#endif // __FUNCTION_NAME__ 

#define DEBUG_PANIC(p) CLogging::Debuglogf("Debug marker (%s) - ::%s() in file: %s(%d)", p, __FUNCTION_NAME__, __FILE__, __LINE__); 

與上面代碼段的問題是,它是的#else宏是在所有的編譯器活性,而其他的宏都沒有。換句話說#if defined __func__在編譯器上是錯誤的,其中__func__預定義的宏

我的問題是

  • 如何創建一個交叉編譯器宏找到函數的名字嗎?
  • 如何判斷是否可以使用__func__
+0

你在寫C或C++嗎? – 2013-03-09 00:01:41

+0

@KeithThompson對不起,我忘了,這增加的問題,是C++ – 2013-03-09 00:28:03

回答

17

你假設__func__是一個宏,但事實並非如此。這是一個有條件支持的預定義標識符,因此您無法使用#if defined#ifdef進行檢查。

如果編譯器無法告訴你這是否被支持(他們可以通過_FUNC_SUPPORTED或其他東西,我不是說他們真的這樣做),你必須檢查編譯器而不是實際的標識符。

東西沿着線:

#ifndef __FUNCTION_NAME__ 
    #ifdef WIN32 //WINDOWS 
     #define __FUNCTION_NAME__ __FUNCTION__ 
    #else   //*NIX 
     #define __FUNCTION_NAME__ __func__ 
    #endif 
#endif 
+9

任何C語言編譯器,符合C99或更高版本*必須*支持'__func__';在這個意義上說,它不是一個可選功能。所以支持'__func__'的一種方法是檢查'__STDC_VERSION__> = 199901L'。 (雖然C99之前或不合規的編譯器可以支持它作爲擴展。) – 2013-03-08 23:59:03

+1

@KeithThompson我假設C++。但重點是它不是一個宏。 – 2013-03-09 00:00:41

+4

啊,好點; OP沒有爲該語言添加標籤。在2011年之前,C++標準沒有強制使用'__func__'。這可能是pre-C++ 11編譯器的常見擴展。 – 2013-03-09 00:04:02

4

我想補充一點,__FUNCTION__宏是爲GCC和MSVC定義的。儘管非標準,但它在兩個編譯器上都可用。

GCC Standard Predefined Macros報價:

C99引入__func__和GCC已經很長一段時間提供__FUNCTION__。這兩個字符串都是包含當前函數名稱的字符串(語義差異很小;請參閱GCC手冊)。它們都不是宏觀的;預處理器不知道當前函數的名稱。不過,它們傾向於與__FILE____LINE__一起使用。

MSVC Predefined Macros報價:

__FUNCTION__

僅在功能有效。將封閉函數的未裝飾名稱定義爲字符串文字。

如果您使用/ EP或/ P編譯器選項,則不會展開__FUNCTION__

查看__FUNCDNAME__舉例。

所以使用__FUNCTION__就可以了,因爲兩個編譯器都實現它。雖然在兩種編譯器上可能得不到相同的結果,但在某些情況下可能可以接受。