C++宏测试__func__,__FUNCTION__,__PRETTY_FUNCTION__等是否可用

4

现代的C/C++编译器通常包含__func__ / __FUNCTION__之一或两者,用于记录当前正在执行的函数。MSVC++还包括__FUNCSIG__和GCC__PRETTY_FUNCTION__,作为这种功能的编译器特定增强版。

然而,GCC将其定义为变量而不是宏,因此无法通过#ifdef预处理器指令来测试其存在性。

我正在使用必须适用于MSVC++和GCC的C++98和C++11版本的代码库,并且某人编写的日志记录设施错误地尝试测试__FUNCTION__是否可用,如果__FUNCSIG__不可用,则失败检查总是返回false,使函数记录支持无法操作。

问题:是否有一个好的宏可以基于编译器版本推测出哪些(如果有)这些功能应该存在,以满足我的用例需求?


1
你可以使用一些“配置”方法,在构建时生成一个小的头文件(阅读有关autoconf的内容)。 - Basile Starynkevitch
2
BOOST_CURRENT_FUNCTION。 - T.C.
2
它位于Boost.Assert下。 - T.C.
3
@T.C. 你能够将你的建议作为一个正式回答发布吗?同时请附上这些链接:http://www.boost.org/doc/libs/1_66_0/libs/assert/doc/html/assert.html#current_function_macro_boost_current_function_hpp 和 http://www.boost.org/doc/libs/1_66_0/boost/current_function.hpp,这样你就能获得相应的信用了。谢谢! - HunterZ
1
@ElmarZander 看来这是为 C 而不是 C++。根据C++标准中的 [dcl.fct.def.general] 部分,“函数本地预定义变量 __func__ 定义为…” (我加重了语气)。 - Some programmer dude
显示剩余10条评论
2个回答

2
T.C.首先在我的问题下面以评论的形式提供了这个答案,我最终基于它来解决问题:
Boost.Assert中的头文件<boost/current_function.hpp>实现了一个BOOST_CURRENT_FUNCTION宏,试图映射到由编译器提供的适当的“当前函数”设施。
文档在这里: http://www.boost.org/doc/libs/1_66_0/libs/assert/doc/html/assert.html#current_function_macro_boost_current_function_hpp 这里是一个简洁的宏复制品以供参考:
#if defined( BOOST_DISABLE_CURRENT_FUNCTION )
# define BOOST_CURRENT_FUNCTION "(unknown)"
#elif defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__)
# define BOOST_CURRENT_FUNCTION __PRETTY_FUNCTION__
#elif defined(__DMC__) && (__DMC__ >= 0x810)
# define BOOST_CURRENT_FUNCTION __PRETTY_FUNCTION__
#elif defined(__FUNCSIG__)
# define BOOST_CURRENT_FUNCTION __FUNCSIG__
#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
# define BOOST_CURRENT_FUNCTION __FUNCTION__
#elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
# define BOOST_CURRENT_FUNCTION __FUNC__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
# define BOOST_CURRENT_FUNCTION __func__
#elif defined(__cplusplus) && (__cplusplus >= 201103)
# define BOOST_CURRENT_FUNCTION __func__
#else
# define BOOST_CURRENT_FUNCTION "(unknown)"
#endif

我最终修改了我正在处理的代码库,以便在可用时使用Boost宏,并在否则情况下退回到合理的子集Boost检查(GCC > MSVC++ > C++11)。


1

__func__ 在 C99 中被定义(但不在 C++ 中),gcc 已经提供了 __FUNCTION____PRETTY_FUNCTION__ 很长时间了。然而,它们都不是宏,因此不能像宏一样使用。这意味着你不能使用 #ifdef 来测试它们。

要测试是否编译为 C++,以及使用的标准是什么,请使用在 C++ 标准中指定的 __cplusplus,它会扩展为值 199711L(C++11 之前)、201103L(C++11)、201402L(C++14)和 201703L(C++17)。这些值对应于标准化委员会批准标准的日期(年份和月份)(例如,201703L 表示 C++17 在 2017 年 3 月获得批准)。请注意,只有在编译 C++ 时才定义此宏。

此外,要使用特定于编译器的功能,需要测试支持所需功能的编译器,而不是测试功能本身(尽管某些编译器/预处理器允许测试特定的语言功能,但实际上这种情况并不普遍)。

gcc和g++(以及其他声称支持GNU C方言的编译器)提供许多特定的宏,因此您可以检查它们,包括:

  • __GNUC__ - 定义为GNU C编译器(可以使用#ifdef进行测试)。对于gcc版本x.y.z__GNUC__扩展为值x
  • __GNUC_MINOR__ - 定义为GNU C编译器(可以使用#ifdef进行测试)。对于gcc版本x.y.z__GNUC_MINOR__扩展为值y
  • __GNUC_PATCH_LEVEL__ - 定义为GNU C编译器(可以使用#ifdef进行测试)。对于gcc版本x.y.z__GNUC_PATCHLEVEL__扩展为值z
  • __GNUG__ - 定义为g++编译器。

以下是如何使用GNU特定宏的示例:

 #ifdef __GNUG__

     /*   Assume all versions of gcc that you use support __FUNCTION__ */

     /*  can use gcc's __FUNCTION__ here   */

 #endif

我不知道从哪个g++版本开始支持__FUNCTION____PRETTY_FUNCTION__,但如果你想测试编译器的特定版本,这很容易。例如,要测试g++ 3.2.0或更高版本:

 #ifdef __GNUG__
 // test for g++ 3.2.0 or better
 #if __GNUC__ > 3 ||                            \ 
       (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \
                   (__GNUC_MINOR__ == 2 &&      \
                    __GNUC_PATCHLEVEL__ > 0))  

        // use features not introduced before g++ 3.2.0

 #endif
 #endif

对于MSVC++,编译器特定的宏用于类似的目的,包括_MSC_VER,它扩展为主要和次要版本的编码。例如,在MSVC++版本17.00.51106.1下,_MSC_VER扩展为1700。您可以在MSDN上找到其他信息。

谢谢。这是我自己的进展,除了显然 MSVC++ 的 __FUNCSIG__ 实际上是一个可以直接测试的宏。最终我从 Boost 那里得到了一个更具体的答案,正如 T.C. 在我的问题评论中建议的那样。 - HunterZ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接