2013-03-08 91 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__就可以了,因为两个编译器都实现它。虽然在两种编译器上可能得不到相同的结果,但在某些情况下可能可以接受。