__func__ 和 __PRETTY_FUNCTION__ 并不总是展开
__func__ and __PRETTY_FUNCTION__ not always expanded
我有一个使用宏来跟踪消息的日志库。此宏使用 __func__
和 __PRETTY_FUNCTION__
等预定义宏来指示消息记录在哪个 function/method 中。
我的日志库的宏定义在我的日志库的主 header 中,在任何函数之外。
出于某种原因,预处理代码包含 __func__
(或者 __PRETTY_FUNCTION__
,如果我正在使用这个),就像这些预定义的宏不存在一样。但我知道它们确实存在,因为如果我在不使用我的库的跟踪宏的情况下使用它们,它们就可以工作!
这是我的库宏:
#if _MSC_VER >= 1400 // If >= VS2005
#define _TRACE_FUNC_SIGNATURE __FUNCSIG__
#elif defined(__ANDROID__) || defined( __GNUC__ ) && defined( __cplusplus ) // If G++ and/or Android NDK
#define _TRACE_FUNC_SIGNATURE __func__
#else
#error // Unsupported compiler
#endif
// Forces the reprocessing of x to properly expand __VA_ARGS__ when using MSVC compiler
#define _TRACE_REPROCESS( x ) x
#define _TRACE_X( _methodName_, _logCatPtr_, ... ) \
do { \
::dbg::LogCategory * const _catPtrVal_ = (::dbg::LogCategory *)(_logCatPtr_); \
if( NULL != _catPtrVal_ && _catPtrVal_->IsEnabled() ) \
{ \
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); ) \
} \
} while( false )
#define TRACE_E( _logCatPtr_, ... ) _TRACE_X( Error, _logCatPtr_, __VA_ARGS__ )
#define TRACE_W( _logCatPtr_, ... ) _TRACE_X( Warning, _logCatPtr_, __VA_ARGS__ )
#define TRACE_I( _logCatPtr_, ... ) _TRACE_X( Info, _logCatPtr_, __VA_ARGS__ )
我知道这些宏没有理由在函数外定义,但由于我只在 functions/methods 内使用我的跟踪宏,所以它应该在那里定义!
我正在使用 eclipse 提供的默认 Android NDK 编译器,据我所知,它是某种扩展的 G++。
EDIT :如果我将 __func__
替换为实际的字符串文字,它就可以工作,没有语法错误。这让我认为 __func__
在我的宏中使用时肯定没有定义。
在某些实现中,__func__
是一个变量,而不是宏 (at least in gcc)。因此,您不能像使用字符串文字一样使用它。
所以,这个:
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); )
将不得不以不同的方式书写。我不知道 _catPtrVal_->_methodName_
是如何实现的,但如果它可以接受多个参数,那么像这样的东西可能会成功:
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE, " - " __VA_ARGS__ ); )
如果不是,那么您将不得不使用其他方式将 __func__
与日志行的其余部分连接起来(例如使用 std::stringstream
)。
更多详情
C 标准规定 __func__
是这样的:
The identifier __func__
shall be implicitly declared by the translator as if,
immediately following the opening brace of each function definition, the declaration
static const char __func__[] = "function-name";
appeared, where function-name is the name of the lexically-enclosing function.
即。是否将其作为变量或宏提供(只要它的行为就像如上所示定义的那样)由实现决定。
例如,gcc provides it as a variable, and MSVC provides it as a macro。
我想我要加两分钱 - 可以在预处理器指令中使用函数签名,但您必须先捕获它。这是一个比较 __PRETTY_FUNCTION__
和预处理器替代方案的示例。
#include <stdio.h>
#define CAT(X,Y) X ## Y
#define VAR(X) X
#define VAR_(X) VAR(X)
#define VAL(X) #X
#define VAL_(X) VAL(X)
/* Alias for constexpr cstring */
#define SZ const char*
#define CE_SZ constexpr SZ
/* Alias for assignment with appended log statement */
#define LOG(X, Y) X = Y; CE_SZ VAR_(CAT(INFO_, X)) = \
VAL_(X) " = " VAL_(Y) " (" __FILE__ VAL_(:__LINE__) ")"
/* SZ_A has no preprocessor value */
CE_SZ SZ_A = "Value of SZ_A";
/* SZ_B only has value to the preprocessor during LOG
(no define from inside a define, macro, etc.) */
CE_SZ LOG(SZ_B, "Value of SZ_B");
/* SZ_C has a global preprocessor name and value, but no compile time name */
#define SZ_C "Value of SZ_C"
/* SZ_D associates a compile time name with the value of SZ_C */
CE_SZ LOG(SZ_D, SZ_C);
/*
__PRETTY_FUNCTION__ and __func__ don't expand to string literals, but
to references to strings initialized by the compiler. If you capture the
signature in a preprocessor define, it's available globally; if you pass
it to a preprocessor macro, it's available within the scope of the macro.
__PRETTY_FUNCTION__ depends on compiler implementation (if it's defined
at all) - parameter names will be missing, template typenames and values
will be enumerated, etc.
*/
#define SIG template<typename T = SZ> void test(T caller)
SIG {
/* int main(int, const char**) */
printf(" Called function: %s\n", caller);
/* void test(T) [with T = const char*] */
printf(" Current function: %s\n", __PRETTY_FUNCTION__);
/* template<typename T = const char*> void test(T caller) */
printf(" Preprocessor signature: " VAL_(SIG) "\n");
}
CE_SZ LOG(SZ_E, VAL_(SIG));
int main(int argc, const char *argv[]) {
/* SZ_A = "Value of SZ_A" */
printf("%s = \"%s\"\n", VAL_(SZ_A), SZ_A);
/* SZ_B = "Value of SZ_B" (main.cpp:26) */
printf("%s\n", INFO_SZ_B);
/* SZ_C = "Value of SZ_C" */
printf("%s\n", "SZ_C = " VAL_(SZ_C));
/* SZ_D = "Value of SZ_D" (main.cpp:32) */
printf("%s\n\n", INFO_SZ_D);
test(__PRETTY_FUNCTION__);
/* SZ_E = "template..." (main.cpp:53) */
printf("\n%s\n", INFO_SZ_E);
}
我有一个使用宏来跟踪消息的日志库。此宏使用 __func__
和 __PRETTY_FUNCTION__
等预定义宏来指示消息记录在哪个 function/method 中。
我的日志库的宏定义在我的日志库的主 header 中,在任何函数之外。
出于某种原因,预处理代码包含 __func__
(或者 __PRETTY_FUNCTION__
,如果我正在使用这个),就像这些预定义的宏不存在一样。但我知道它们确实存在,因为如果我在不使用我的库的跟踪宏的情况下使用它们,它们就可以工作!
这是我的库宏:
#if _MSC_VER >= 1400 // If >= VS2005
#define _TRACE_FUNC_SIGNATURE __FUNCSIG__
#elif defined(__ANDROID__) || defined( __GNUC__ ) && defined( __cplusplus ) // If G++ and/or Android NDK
#define _TRACE_FUNC_SIGNATURE __func__
#else
#error // Unsupported compiler
#endif
// Forces the reprocessing of x to properly expand __VA_ARGS__ when using MSVC compiler
#define _TRACE_REPROCESS( x ) x
#define _TRACE_X( _methodName_, _logCatPtr_, ... ) \
do { \
::dbg::LogCategory * const _catPtrVal_ = (::dbg::LogCategory *)(_logCatPtr_); \
if( NULL != _catPtrVal_ && _catPtrVal_->IsEnabled() ) \
{ \
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); ) \
} \
} while( false )
#define TRACE_E( _logCatPtr_, ... ) _TRACE_X( Error, _logCatPtr_, __VA_ARGS__ )
#define TRACE_W( _logCatPtr_, ... ) _TRACE_X( Warning, _logCatPtr_, __VA_ARGS__ )
#define TRACE_I( _logCatPtr_, ... ) _TRACE_X( Info, _logCatPtr_, __VA_ARGS__ )
我知道这些宏没有理由在函数外定义,但由于我只在 functions/methods 内使用我的跟踪宏,所以它应该在那里定义!
我正在使用 eclipse 提供的默认 Android NDK 编译器,据我所知,它是某种扩展的 G++。
EDIT :如果我将 __func__
替换为实际的字符串文字,它就可以工作,没有语法错误。这让我认为 __func__
在我的宏中使用时肯定没有定义。
在某些实现中,__func__
是一个变量,而不是宏 (at least in gcc)。因此,您不能像使用字符串文字一样使用它。
所以,这个:
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); )
将不得不以不同的方式书写。我不知道 _catPtrVal_->_methodName_
是如何实现的,但如果它可以接受多个参数,那么像这样的东西可能会成功:
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE, " - " __VA_ARGS__ ); )
如果不是,那么您将不得不使用其他方式将 __func__
与日志行的其余部分连接起来(例如使用 std::stringstream
)。
更多详情
C 标准规定 __func__
是这样的:
The identifier
__func__
shall be implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration
static const char __func__[] = "function-name";
appeared, where function-name is the name of the lexically-enclosing function.
即。是否将其作为变量或宏提供(只要它的行为就像如上所示定义的那样)由实现决定。
例如,gcc provides it as a variable, and MSVC provides it as a macro。
我想我要加两分钱 - 可以在预处理器指令中使用函数签名,但您必须先捕获它。这是一个比较 __PRETTY_FUNCTION__
和预处理器替代方案的示例。
#include <stdio.h>
#define CAT(X,Y) X ## Y
#define VAR(X) X
#define VAR_(X) VAR(X)
#define VAL(X) #X
#define VAL_(X) VAL(X)
/* Alias for constexpr cstring */
#define SZ const char*
#define CE_SZ constexpr SZ
/* Alias for assignment with appended log statement */
#define LOG(X, Y) X = Y; CE_SZ VAR_(CAT(INFO_, X)) = \
VAL_(X) " = " VAL_(Y) " (" __FILE__ VAL_(:__LINE__) ")"
/* SZ_A has no preprocessor value */
CE_SZ SZ_A = "Value of SZ_A";
/* SZ_B only has value to the preprocessor during LOG
(no define from inside a define, macro, etc.) */
CE_SZ LOG(SZ_B, "Value of SZ_B");
/* SZ_C has a global preprocessor name and value, but no compile time name */
#define SZ_C "Value of SZ_C"
/* SZ_D associates a compile time name with the value of SZ_C */
CE_SZ LOG(SZ_D, SZ_C);
/*
__PRETTY_FUNCTION__ and __func__ don't expand to string literals, but
to references to strings initialized by the compiler. If you capture the
signature in a preprocessor define, it's available globally; if you pass
it to a preprocessor macro, it's available within the scope of the macro.
__PRETTY_FUNCTION__ depends on compiler implementation (if it's defined
at all) - parameter names will be missing, template typenames and values
will be enumerated, etc.
*/
#define SIG template<typename T = SZ> void test(T caller)
SIG {
/* int main(int, const char**) */
printf(" Called function: %s\n", caller);
/* void test(T) [with T = const char*] */
printf(" Current function: %s\n", __PRETTY_FUNCTION__);
/* template<typename T = const char*> void test(T caller) */
printf(" Preprocessor signature: " VAL_(SIG) "\n");
}
CE_SZ LOG(SZ_E, VAL_(SIG));
int main(int argc, const char *argv[]) {
/* SZ_A = "Value of SZ_A" */
printf("%s = \"%s\"\n", VAL_(SZ_A), SZ_A);
/* SZ_B = "Value of SZ_B" (main.cpp:26) */
printf("%s\n", INFO_SZ_B);
/* SZ_C = "Value of SZ_C" */
printf("%s\n", "SZ_C = " VAL_(SZ_C));
/* SZ_D = "Value of SZ_D" (main.cpp:32) */
printf("%s\n\n", INFO_SZ_D);
test(__PRETTY_FUNCTION__);
/* SZ_E = "template..." (main.cpp:53) */
printf("\n%s\n", INFO_SZ_E);
}