我有一个使用宏来跟踪消息的日志库。此宏使用预定义的宏(如__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__
肯定没有定义。
答案 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 variable和MSVC 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);
}