错误定义宏

4人阅读 评论(0) 收藏 举报

[前言:使用__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()来报告错误,以使当某个错误发生时我能设置断点以及隔离错误处理(例如,在屏幕上打印错误信息或者写入日志)。因此,函数的原型应该是这样的吧:

void  error( const   char   * file,  const  unsigned  long  line, const   char   * msg); 


调用方式如下:

error(__FILE__, __LINE__,  " my error message " );


预处理魔法

这里有三个问题需要解决:

  1. __FILE__和__LINE__在每次调用error时作为参数传入。
  2. __FILE和__LINE__前后的下划线很容易被遗忘,从而导致编译错误。
  3. __LINE__是一个整数,这无疑增加了error函数的复杂度。我绝不想直接使用整型的__LINE__,而通常都是将转换为字符串打印到屏幕或写入日志文件。

__FILE__和__LINE__应该被自动处理,而非每次作为参数传递给error,这样会让error的使用者感觉更爽些,它的形式可能是下面这样:

error(AT,  " my error message " );

 
我希望上面的宏AT展开为:"c:\temp\test.cpp:5"。而新的error函数则变成:

void  error( const   char   * location,  const   char   * msg);

 

 

因为Borland C++ Builder编译器能够自动合并相邻的字符串,因此我把AT写成下面这样:

#define  AT __FILE__ ":" __LINE__ 


然而它却罢工了,因为__LINE__被扩展成了整数而非字符串,所以宏展开后变成:

"c:\temp\test.cpp" ":"
 5

这是一个无效的字符串,因为末尾有一个未被双引号包含的整数。

怎么办?别着急,一个特殊的预编译指示器“#”能够帮我们将一个变量转换成字符串。所以重新定义宏:

#define AT __FILE__ ":" #__LINE__
嘿嘿,这样总行了吧。别高兴得太早,这样也是不行的。因为编译器会抱怨#是个无效字符。其实,问题是#预编译指示器只有这样使用才会
被正确识别:

#define symbol(X) #X 


因此,我把代码改为:

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


然而,奇怪的结果产生了,__LINE__居然被作为了输出的一部分:

c:\temp\test.cpp:__LINE__: fake error

解决方法是再用一个宏来包装STRINGIFY():

#define  STRINGIFY(x) #x 
#define  TOSTRING(x) STRINGIFY(x) 
#define  AT __FILE__ ":" TOSTRING(__LINE__) 


OK,我们用下面的代码来试试:

#include  < stdio.h > 
#define  STRINGIFY(x) #x 
#define  TOSTRING(x) STRINGIFY(x) 
#define  AT __FILE__ ":" TOSTRING(__LINE__) 
void  error( const   char   * location,  const   char   * msg)
{
  printf(
 " Error at %s: %s\n " , location, msg);
}
int  main( int  ,  char ** )
{
  error(AT, 
 " fake error " );
  
 return   0 ;
}


输出结果:

Error at c:\temp\test\test.cpp:11: fake error

Visual Studio下的实践
在《Windows核心编程》中,Jeffrey Richter提供了下面的宏在编译期输出有用信息: 

#define  chSTR2(x) #x 
#define  chSTR(x)  chSTR2(x) 
#define  chMSG(desc) message(__FILE__ "(" chSTR(__LINE__) "):" #desc)

message是一个预编译指令,上面宏的使用方法是:

 

 #pragma chMSG(Fix  this  later)


结论

  1. 预编译指示器__FILE__和__LINE__能够提供有用的信息。
  2. __LINE__的处理方式远比我们想象的要复杂。
  3. __FILE__被处理成字符串,给我们带来了不少方便。
查看评论

Clang 宏定义初探(一)

Clang 宏定义初探(一)宏的定义方法是#define 那么在什么场景下需要用到宏呢?遇到一些重复的东西,简单的有 for(i = 0; i < n; i ++) 之类的,为了减少繁琐的编码,可能...
  • superlong100
  • superlong100
  • 2016-03-11 01:34:07
  • 291

Android.mk 宏定义

PLATFORM_VERSION:= 2.1 LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS)   LOCAL_SRC_FILES:= ...
  • stefzeus
  • stefzeus
  • 2011-08-08 15:23:36
  • 4404

VS2010编写自定义宏

这里所说的宏可不是指#define PI 3.14159之类的,而是按下Alt + 1,Alt + 2之类的键盘组合之后可以方便地插入一大串自定义的内容,如: /******************...
  • ajioy
  • ajioy
  • 2013-01-08 22:38:51
  • 9424

C++开发预定义宏——以VS2010为例

ANSI C macro宏定义下表提供了这七个预定义宏,某些宏可以被定义为多个值。 Macro Description __DATE__ 当前代码的编译时间。date格式为Mmm dd ...
  • u011511587
  • u011511587
  • 2016-08-22 10:12:13
  • 715

Unity 宏定义

http://docs.unity3d.com/Manual/PlatformDependentCompilation.html
  • mengfanye1991
  • mengfanye1991
  • 2016-08-26 11:01:57
  • 347

Clang 宏定义初探(二)

Clang 宏定义初探(二)本篇总结下这几天看的宏的一些看到的用法。1、参数粘结这是一个类似 shell 之类的脚本语言的特性,可以利用这个特性完成一些重复度比较高的编码的简化。 例如,对proc文...
  • superlong100
  • superlong100
  • 2016-03-11 01:39:14
  • 265

QT全局宏变量的实现

qt中如何实现定义一个宏,在整个工程中都可以实现呢?下面我来写一个亲测的例子: pro中添加如下宏定义代码: DEFINES += HELLO=\\\"$$PWD/\\\" DEFINES += ...
  • u013639526
  • u013639526
  • 2015-02-28 11:36:53
  • 2214

erlang 宏定义

转自:http://www.cnblogs.com/me-sa/archive/2011/07/20/erlang0006.html
  • uxh2007
  • uxh2007
  • 2013-07-08 23:02:58
  • 2411

第二周项目二——程序的多文件组织

/*烟台大学计算机学院 文件名称:san.cpp main.cpp sss.h 作者:董玉祥 完成日期: 2017年9月17日 问题描述: (1) .h 头文件:定义数据类型...
  • dongyuxiangi
  • dongyuxiangi
  • 2017-09-17 14:23:10
  • 98

max 宏定义取消:error C2589: error C2059: 语法错误 : “::”

使用PCL和windows过程中,maxmin问题是一个大问题
  • wishchin
  • wishchin
  • 2013-10-18 16:39:19
  • 2343
    个人资料
    等级:
    访问量: 89
    积分: 111
    排名: 125万+
    文章分类
    文章存档
    最新评论