函数体中打印日志信息自动附加函数名字的一种实现办法
2012-05-05 21:54
519 查看
一段代码,在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的定义
#ifdefined(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~相关文章推荐
- C打印函数printf的一种实现原理简要分析
- 调试信息的宏定义:能够打印出文件名、函数、行数、日志,方便调试
- C#实现为类和函数代码自动添加版权注释信息的方法
- 使用printf函数实现串口信息打印——设置IAR和Keil的Options
- SecureCRT自动记录日志【记录键入的所有命令和打印的结果信息】
- MFC 一种比较笨的办法实现多线程执行类成员函数
- 可以打印栈信息的日志函数,移动混合开发必备!!!
- 一种基于浏览器的自动小票机打印实现方案(js版)
- 调用bool函数的时候如果函数return false。自动打印日志并return false,有兴趣可以拿来玩玩用
- 一种基于浏览器的自动小票机打印实现方案(js版)
- 可以打印栈信息的日志函数,移动混合开发必备!!!
- C#实现为类和函数代码自动添加版权注释信息的方法
- C打印函数printf的一种实现原理简要分析
- ASP实现长文章自动分页的函数代码
- C++写日志源代码分析,可实现根据日期自动创建文件夹、日志分类、文件大小控制等
- python自定义输入名字并打印-学习笔记10-输入函数
- Shell实现自动更新目录名称与文件中版本号信息与时间戳
- 三种模拟自动登录和提交POST信息的实现方法
- 用js实现自动获取身份证里面的信息
- 打印文件行数函数信息,定位信息