【问题标题】:__func__ and __PRETTY_FUNCTION__ not always expanded__func__ 和 __PRETTY_FUNCTION__ 并不总是展开
【发布时间】:2015-11-19 13:43:39
【问题描述】:

我有一个使用宏来跟踪消息的日志库。此宏使用预定义的宏,如 __func____PRETTY_FUNCTION__ 来指示消息记录在哪个函数/方法中。

我的日志库的宏在我的日志库的主标题中定义,在任何函数之外。

由于某种原因,预处理代码包含__func__(或__PRETTY_FUNCTION__,如果我正在使用这个),就像这些预定义的宏不存在一样。但我知道它们确实存在,因为如果我在不使用 lib 的跟踪宏的情况下使用它们,它们就可以工作!

这是我的库宏:

#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__ )

我知道这些宏没有理由在函数之外定义,但由于我只在函数/方法中使用我的跟踪宏,所以它应该在那里定义!

我正在使用 eclipse 提供的默认 Android NDK 编译器,据我所知,它是某种扩展的 G++。

EDIT :如果我将__func__ 替换为实际的字符串,它可以工作,没有语法错误。这让我觉得__func__ 在我的宏中使用时肯定没有定义。

【问题讨论】:

  • 感谢您的评论。不幸的是,我得到了同样的结果。
  • 我查看了有__func__ " - " ... 的预处理代码,这给了我一个错误,因为变量不能只跟这样的字符串。如果__func__ 是一个宏,它会扩展为一个字符串,编译器会将它添加到" - "

标签: c gcc macros g++


【解决方案1】:

在某些实现中,__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__

标识符__func__ 应由翻译器隐式声明,就好像, 紧跟在每个函数定义的左大括号之后,是声明

static const char __func__[] = "function-name";

出现了,其中 function-name 是词法封闭函数的名称。

即。是否将其作为变量或宏提供(只要它的行为就像如上所示定义一样),由实现决定。

例如,gcc provides it as a variableMSVC provides it as a macro

【讨论】:

  • 感谢您的回答。我认为看到__ 是一个宏,因为__FUNCSIG__ 是MSVC 上的一个宏。如果它是一个宏会很方便,因为我可以在编译时简单地连接它。
  • @Virus721 :不幸的是,C 标准只要求:“标识符 __func__ 应由翻译器隐式声明,就好像紧跟在每个函数定义的左大括号之后,声明 @987654337 @出现了。”。我不知道 MSVC 将它作为宏提供,但你不能依赖其他实现做同样的事情。
【解决方案2】:

我想我会加两分钱 - 可​​以在预处理器指令中使用函数签名,但你必须先捕获它。这是一个比较 __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);
}

【讨论】:

    猜你喜欢
    • 2014-06-07
    • 2015-10-04
    • 2011-05-22
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多