函数体中打印日志信息自动附加函数名字的一种实现办法

17 篇文章 0 订阅
14 篇文章 0 订阅

一段代码,在Windows下的VC环境下编译没问题,在Linux的GCC下会报一个错误:

error : L__FUNCTION__ was not declared in this scope 

对此的解释:

In GCC 3.3 and earlier, in C only, __FUNCTION__ and __PRETTY_FUNCTION__ were treated as string literals; they could be used to initialize char arrays, and they could be concatenated with other string literals. GCC 3.4 and later treat them as variables, like __func__. In C++, __FUNCTION__ and __PRETTY_FUNCTION__ have always been variables.

 

引发此问题的代码段如下:

 
1)定义
 
#define FH(fmt) TEXT(__FUNCTION__)TEXT(" >> ")fmt
#define FHT(fmt) FH(__TEXT(fmt))
 
2)写日志的函数
 
void SSLogPrintT(LPCTSTR lpInfo)
{
    // Write the <lpInfo> to My Log Pool
    _tprintf_s(lpInfo);
}
 
3)使用场景
 
void Test_Log_Function()
{
    SSLogPrintT(FHT("I'm here!\r\n"));
}
 
4)预期结果
 
Test_Log_Function >> I'm here!
 
5)在Linux的GCC环境下有此定义
 
#ifdef _UNICODE
typedef wchar_t TCHAR;
#define __T(x)            L ## x
#define __TEXT(x)        L##x
#else
typedef char TCHAR;
#define __T(x)            x
#define __TEXT(x)        x
#endif
#define _T(x)            __T(x)
#define _TEXT(x)        __T(x)
#ifndef TEXT
#define TEXT(x)            __TEXT(x)
#endif
 
typedef TCHAR            _TCHAR;
typedef wchar_t WCHAR;
typedef char CHAR;
typedef TCHAR *LPTSTR, *PTCHAR;
typedef CONST TCHAR *LPCTSTR, *PCTSTR;
typedef CHAR *LPSTR, *PSTR;
typedef CONST CHAR *LPCSTR, *PCSTR;
typedef WCHAR            *LPWSTR, *PWSTR;
typedef CONST WCHAR        *LPCWSTR, *PCWSTR;
 
#ifndef wprintf_s
#define wprintf_s    unix_wprintf
#endif
#ifndef printf_s
#define printf_s    printf
#endif
#ifdef _UNICODE
#define _tprintf_s        printf_s
#else
#define _tprintf_s        sprintf_s
#endif
 

好了,开始分析问题:

上面一段English总的意思是说对于版本号等于大于3.4的GCC编译器, 它会把定义__FUNCTION__认为是当前函数的窄字符形式的名字,但是L__FUNCTION__编译器并不会认为这是__FUNCTION__的宽字符形式,而认为它是一个名为L__FUNCTION__的变量,而这个变量并没有定义,所以编译器在编译的时候会直接报错.
可是如果我还想用
    SSLogPrintT(FHT("I'm here!\r\n"));
的形式来用,怎么办?
 
可以看到错误主要在FH的定义处,如果能用一种办法直接替换TEXT(__FUNCTION__)为宽字符形式,那么问题也解决了.
 

方案如下:

在windows平台下,定义MP_WINDOWS宏,仍然用上面的定义,在LINUX下面则用工具类CSSCoreLogUtilFmtWithFUNCNameA /W来辅助生成宽字符串.
 
修改FH的定义
#if defined(MP_WINDOWS)
#define FH(fmt) TEXT(__FUNCTION__)TEXT(" >> ")fmt
#else
#if defined(_UNICODE)
#define FH(fmt) CSSCoreLogUtilFmtWithFUNCNameW(__FUNCTION__, TEXT(" >> ")fmt)
#else
#define FH(fmt) CSSCoreLogUtilFmtWithFUNCNameA(__FUNCTION__, " >> "fmt)
#endif
#endif
 

辅助类定义如下:

class CSSCoreLogUtilFmtWithFUNCNameW
{
public:
    CSSCoreLogUtilFmtWithFUNCNameW(const char *lpName, const wchar_t *lpFmt);
    ~CSSCoreLogUtilFmtWithFUNCNameW();
    operator wchar_t* ();
protected:
    wchar_t *m_pStringW;
};
class CSSCoreLogUtilFmtWithFUNCNameA
{
public:
    CSSCoreLogUtilFmtWithFUNCNameA(const char *lpName, const char *lpFmt);
    ~CSSCoreLogUtilFmtWithFUNCNameA();
    operator char* ();
protected:
    char *m_pStringA;
};
 
呵呵,实现不写了,麻烦,大体意思是
类CSSCoreLogUtilFmtWithFUNCNameW在构造函数中接受窄字符的函数名字(lpName)和宽字符的格式化参数(lpFmt),把他们复合成宽字符的数据,放入m_pStringW中,m_pStringW会在重载函数operator wchar_t* ()中返回;
类CSSCoreLogUtilFmtWithFUNCNameA在构造函数中接受窄字符的函数名字(lpName)和窄字符的格式化参数(lpFmt),把他们复合成窄字符的数据,放入m_pStringA中,m_pStringA会在重载函数operator char* ()中返回;
 

到原理了吧 - 很简单

因为
    SSLogPrintT(FHT("I'm here!\r\n"));
这种调用格式,可以看到FHT,FH会在一个()域中,我们可以在()域中定义一个临时类的实例A,它的构造参数接受函数名和格式化参数两个字符串,它可以隐式转换为宽/窄字符的字符串,
函数SSLogPrintT执行体的域(即{})跟此临时类的实例所在的域()是相同的,所以在函数SSLogPrintT的函数实现体内,A还是存在的,我们完全可以利用从A隐性转化来的窄/宽字符.
在SSLogPrintT退出之后,域()消失,临时变量A的析构函数会被调用到,可以再此处释放A动态分配的临时变量(如果有的话).
 

总结

在VC环境下很简单的东西,在GCC下可能就会出现各种状况. O(∩_∩)O~
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值