英文原帖:http://www.decompile.com/cpp/faq/file_and_line_error_string.htm
翻译原帖:http://www.cppblog.com/heath/archive/2008/08/05/58046.html
[前言:使用__FILE__和__LINE__来定位错误已经屡见不鲜,然而其中一些道理又有几个人仔细探究过。本文参考了Curtis Krauskopf的一篇名为Using __FILE__ and __LINE__ to Report Errors的文章,希望达到解惑之效。]
问题:当运行时错误产生时,我怎样才能得到包含C++文件名和行号的字符串信息?
回答:在C++中的__FILE__预编译指示器包含了被编译的文件名,而__LINE__则包含了源代码的行号。__FILE__和__LINE__的前后都包含了两个下划线,让我们仔细看看__FILE__所包含的每个字符:
_ _ F I L E _ _
下面展示了在控制台程序中如果显示文件名和代码行号。
#include <stdio.h>
int main(int , char**)
{
printf("This fake error is in %s on line %d\n", __FILE__, __LINE__);
return 0;
}
输出结果:
This fake error is in c:\temp\test.cpp on line 5
我想通过一个通用函数error()来报告错误,以使当某个错误发生时我能设置断点以及隔离错误处理(例如,在屏幕上打印错误信息或者写入日志)。因此,函数的原型应该是这样的吧:
这里有三个问题需要解决:
__FILE__和__LINE__应该被自动处理,而非每次作为参数传递给error,这样会让error的使用者感觉更爽些,它的形式可能是下面这样:
我希望上面的宏AT展开为:"c:\temp\test.cpp:5"。而新的error函数则变成:
因为Borland C++ Builder编译器能够自动合并相邻的字符串,因此我把AT写成下面这样:
然而它却罢工了,因为__LINE__被扩展成了整数而非字符串,所以宏展开后变成:
"c:\temp\test.cpp" ":" 5
这是一个无效的字符串,因为末尾有一个未被双引号包含的整数。
怎么办?别着急,一个特殊的预编译指示器“#”能够帮我们将一个变量转换成字符串。所以重新定义宏:
#define AT __FILE__ ":" #__LINE__
嘿嘿,这样总行了吧。别高兴得太早,这样也是不行的。因为编译器会抱怨#是个无效字符。其实,问题是#预编译指示器只有这样使用才会 被正确识别:#define symbol(X) #X
解决方法是再用一个宏来包装STRINGIFY():