• 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.
    ", __FILE__, __LINE__);
    6     return 0;
    7 }

    Result:

    This fake error is in "C: emp est.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: emp est.cpp: 4"传入到第一个参数中。

          我们可以定义一个宏归并这两个宏:

    #define AT __FILE__ ": " __LINE__

          但是不要忘了__LINE__是一个整数,这个宏AT将被拓展为   

    "C:	emp	est.cpp" ": " 4

          末尾包含了整数不能结合成有效的字符串,编译将出错。

          特殊的预编译指示器"#"能将一个变量转成字符串,可以重新定义宏AT:

    #define AT __FILE__ ": " #__LINE__

          但是编译器会指出"#"是个无效的字符。因为"#"只有这样使用,预编译指示器才能正确识别:

    #define SYMBAL(x) #x

          所以,继续修改代码:

    #define STRINGFY(x) #x
    #define AT __FILE__ ": " STRINGFY(__LINE__)

    结果却是:

    C: emp est.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.
    ", locaton, msg);
    10 }
    11 
    12 int main(int, char**)
    13 {
    14     error(AT, "fake error");
    15     return 0;
    16 }

    Result:

    Error at C: emp est.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

  • 相关阅读:
    css去掉iPhone、iPad默认按钮样式
    STL~Deque简介
    Centos 7 ssh登录速度慢
    C++ delete 两次
    编译gdb 报错 No module named gdb.frames
    gdb 脚本
    转载: CentOS/Linux 解决 SSH 连接慢
    百度经验:Win10查看已存储WiFi密码的两种方法
    git 操作
    Avoiding memory leaks in POSIX thread programming, 多线程避免内存泄漏
  • 原文地址:https://www.cnblogs.com/yooyoo/p/4717917.html
Copyright © 2020-2023  润新知