C/C++中的__FUNCTION__,__FILE__和__LINE__
C/C++提供了三个宏__FUNCTION__,__FILE__和__LINE__来定位程序运行时的错误。程序预编译时预编译器将用所在的函数名,文件名和行号替换。当运行时错误产生后这三个宏分别能返回错误所在的函数,所在的文件名和所在的行号。
Code:
1 #include <stdio.h> 2 3 int main(int, char**) 4 { 5 printf("This fake error is in \"%s\" on line %d.\n", __FILE__, __LINE__); 6 return 0; 7 }
Result:
This fake error is in "C:\temp\test.cpp" on line 4.
在设计程序时可以使用一个error()函数来报告错误,当错误发生时能设置断点或者做其他错误处理(异常抛出,打印到磁盘文件或者屏幕中)。
可以这样设计函数原型:
void error(const char* file, const unsigned long line, const char* msg);
应该这样调用该函数:
error(__FILE__, __LINE__, "an error message triggered.");
也就是说每当调用函数error的时候前两个参数总要用这两个宏填充,这样很麻烦,需要用更好的方法解决:
void error(const char* location, const char* msg);
需要将__FILE__和__LINE__转成"C:\temp\test.cpp: 4"传入到第一个参数中。
我们可以定义一个宏归并这两个宏:
#define AT __FILE__ ": " __LINE__
但是不要忘了__LINE__是一个整数,这个宏AT将被拓展为
"C:\temp\test.cpp" ": " 4
末尾包含了整数不能结合成有效的字符串,编译将出错。
特殊的预编译指示器"#"能将一个变量转成字符串,可以重新定义宏AT:
#define AT __FILE__ ": " #__LINE__
但是编译器会指出"#"是个无效的字符。因为"#"只有这样使用,预编译指示器才能正确识别:
#define SYMBAL(x) #x
所以,继续修改代码:
#define STRINGFY(x) #x #define AT __FILE__ ": " STRINGFY(__LINE__)
结果却是:
C:\temp\test.cpp: __LINE__ : fake error
解决的方法是再用一个宏来包装STRINGFY(x),这一点类似于VC中的_T()宏的写法
最终的正确代码为:
1 #include <stdio.h> 2 3 #define STRINGFY(x) _STRINGFY(x) 4 #define _STRINGFY(x) #x 5 #define AT __FILE__ ": " STRINGFY(__LINE__) 6 7 void error(const char* location, const char* msg) 8 { 9 printf("Error at %s: %s.\n", locaton, msg); 10 } 11 12 int main(int, char**) 13 { 14 error(AT, "fake error"); 15 return 0; 16 }
Result:
Error at C:\temp\test.cpp: 13: fake error
以上环境是在多字节的情况下,如果当前环境是Unicode时,情况稍许有些变化,毕竟是单字符的字符串替换__FUNCTION__宏而非宽字符,需要参考VC中的_T()宏的写法做修改,使这些单字符串的宏同样也能应用于宽字符。
Code:
1 // The code to demonstrate how to convert __FUNCTION__ macro to a unicode string 2 void FuncChar(char* p) {} 3 void FuncWChar(wchar_t* p) {} 4 5 int _tmain(int argc, _TCHAR* argv[]) 6 { 7 // use L for wchar_t 8 FuncChar("hello world!"); 9 FuncWChar(L"hello world!"); 10 // The __FUNCTION__ macro is char type string 11 FuncChar(__FUNCTION__); 12 // FuncWChar(__FUNCTION__); // error C2664 : 'FuncWChar' : cannot convert parameter 1 from 'const char [6]' to 'wchar_t *' 13 #define _L(x) __L(x) 14 #define __L(x) L##x 15 FuncWChar( _L(__FUNCTION__) ); 16 //FuncWChar( __L(__FUNCTION__) ); // error C2065 : 'L__FUNCTION__' : undeclared identifier 17 18 return 0; 19 }
参考博文:
http://www.decompile.com/cpp/faq/file_and_line_error_string.htm
http://www.cppblog.com/heath/archive/2008/08/05/58046.html
http://www.cnblogs.com/aoaoblogs/archive/2009/12/14/1623438.html