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

posted on 2014-10-30 10:51  喵王  阅读(5861)  评论(1编辑  收藏  举报

导航