__func__和__PRETTY_FUNCTION__并不总是展开

时间:2015-11-19 13:43:40

标签: c gcc macros g++

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

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

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

这是我的libs宏:

#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 ++。

编辑:如果我用实际的字符串文件替换__func__,它可以正常工作,没有语法错误。这让我认为在我的宏中使用__func__肯定没有定义。

2 个答案:

答案 0 :(得分:5)

在某些实现中,public function paypalIPNListenerAction(){ // CONFIG: Enable debug mode. This means we'll log requests into 'ipn.log' in the same directory. // Especially useful if you encounter network errors or other intermittent problems with IPN (validation). // Set this to 0 once you go live or don't require logging. define("DEBUG", 1); // Set to 0 once you're ready to go live // define("USE_SANDBOX", 1); define("USE_SANDBOX", 0); define("LOG_FILE", "ipn.log"); // Read POST data // reading posted data directly from $_POST causes serialization // issues with array data in POST. Reading raw POST data from input stream instead. $raw_post_data = file_get_contents('php://input'); $raw_post_array = explode('&', $raw_post_data); $myPost = array(); foreach ($raw_post_array as $keyval) { $keyval = explode ('=', $keyval); if (count($keyval) == 2) $myPost[$keyval[0]] = urldecode($keyval[1]); } // read the post from PayPal system and add 'cmd' $req = 'cmd=_notify-validate'; if(function_exists('get_magic_quotes_gpc')) { $get_magic_quotes_exists = true; } foreach ($myPost as $key => $value) { if($get_magic_quotes_exists == true && get_magic_quotes_gpc() == 1) { $value = urlencode(stripslashes($value)); } else { $value = urlencode($value); } $req .= "&$key=$value"; } // Post IPN data back to PayPal to validate the IPN data is genuine // Without this step anyone can fake IPN data if(USE_SANDBOX == true) { $paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"; } else { $paypal_url = "https://www.paypal.com/cgi-bin/webscr"; } $ch = curl_init($paypal_url); if ($ch == FALSE) { return FALSE; } curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); if(DEBUG == true) { curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLINFO_HEADER_OUT, 1); } // Set TCP timeout to 30 seconds curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close')); // CONFIG: Please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set the directory path // of the certificate as shown below. Ensure the file is readable by the webserver. // This is mandatory for some environments. $cert = __DIR__ . "/../../../../web/cacert.pem"; curl_setopt($ch, CURLOPT_CAINFO, $cert); $res = curl_exec($ch); if (curl_errno($ch) != 0) // cURL error { if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "Can't connect to PayPal to validate IPN message: " . curl_error($ch) . PHP_EOL, 3, LOG_FILE); } curl_close($ch); exit; } else { // Log the entire HTTP response if debug is switched on. if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "HTTP request of validation request:". curl_getinfo($ch, CURLINFO_HEADER_OUT) ." for IPN payload: $req" . PHP_EOL, 3, LOG_FILE); error_log(date('[Y-m-d H:i e] '). "HTTP response of validation request: $res" . PHP_EOL, 3, LOG_FILE); } curl_close($ch); } // Inspect IPN validation result and act accordingly // Split response headers and payload, a better way for strcmp $tokens = explode("\r\n\r\n", trim($res)); $res = trim(end($tokens)); error_log(date('[Y-m-d H:i e] ')." verified ? : ".strcmp($res, 'VERIFIED')." $res : ".$res. PHP_EOL, 3, LOG_FILE); if(DEBUG == true) error_log(date('[Y-m-d H:i e] ')." verified ? : ".strcmp($res, "VERIFIED")." response : ".$res); if (strcmp ($res, "VERIFIED") == 0) { $em = $this->getdoctrine(); $manager = $em->getmanager(); $id = $myPost['custom']; $payment_status = $myPost['payment_status']; $payment_amount = $myPost['mc_gross']; $payment_currency = $myPost['mc_currency']; $txn_id = $myPost['txn_id']; $receiver_email = $myPost['receiver_email']; $processed = $em->getrepository("ArtforsmileMainBundle:Panier")->getbytxn($txn_id); if(!$processed && $payment_status == "completed" && $payment_currency == "eur" && $receiver_email == "xxxxxxxxxxx@xxxxx.xxxxx"){ /* Interacting with the database */ } if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "Verified IPN: $req ". PHP_EOL, 3, LOG_FILE); } } else if (strcmp ($res, "INVALID") == 0) { // log for manual investigation // Add business logic here which deals with invalid IPN messages if(DEBUG == true) { error_log(date('[Y-m-d H:i e] '). "Invalid IPN: $req" . PHP_EOL, 3, LOG_FILE); } } return new Response("ok", Response::HTTP_OK, array('Content-Type' => 'text/plain')); } 是变量,而不是宏(at least in gcc)。所以,你不能像使用字符串文字一样使用它。

所以,这个:

__func__

必须以不同的方式书写。我不知道_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); ) 是如何实现的,但是如果它可以采用多个参数,那么类似这样的东西可能会起到作用:

_catPtrVal_->_methodName_

如果没有,那么您将不得不使用其他方式将_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE, " - " __VA_ARGS__ ); ) 与日志行的其余部分连接起来(使用std::stringstream例如。)。

更多详情

C标准指定__func__,如下所示:

  

标识符__func__应由翻译者隐式声明,如果,   紧跟在每个函数定义的左大括号后面的声明

     

__func__

     

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

IE中。无论是将其作为变量还是宏(只要它的行为就像上面所示定义的那样),它就会将其留给实现。

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

答案 1 :(得分:1)

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