您的位置:首页 > 编程语言 > C语言/C++

关于C语言宏展开的一个问题

2014-06-02 16:16 435 查看
因为以前写的代码更多的是Java的代码,很少接触C或者C++语言,最近在阅读一个项目的C语言源代码的时候,

感觉到自己相当缺乏C语言的基础知识,于是给自己下了要好好学习一下C语言的指令,再于是,现在在学习《一站式学习C编程》这一本书。

在看到P310页关于宏展开的时候,有一个问题困扰了我一下,现在把他记录下来,以便自己以后的复习。

这是一个关于assert.h的自定义实现。

/*assert.h */
#undef assert
#ifdef NDEBUG
#define assert(test)  ((void)0)
#else
void    _Assert (char *);
#define  _STR(x)    _VAL(x)
#define  _VAL(x)    #x
#define  assert(test) ((test) ? (void)0 :_Assert(__FILE__ ":" _STR(__LINE__) " "  #test))
#endif



省略条件判断条件成立的说明。

假设main.c文件的第33行调用assert(is_sorted()),那么__FILE__是字符串"main.c",_LINE_是整数33,#test是字符串“is_sorted()”。

注意_STR(__LINE__)的展开过程:首先展开成_VAL(33),然后进一步展开成字符串“33”。这样,最后_Assert调用的形式是_Assert("main.c" ":" "33" " " "is_sorted()"),

传给_Assert函数的字符串是“main.c:33 is_sorted()”.

问题:请结合前面讲过的宏展开步骤思考一下,为什么不直接定义#define _STR(x) #x呢?

原因:C语言的宏展开有一条规则:除了带#和##运算符的参数之外,其他参数在替换之前要对实参本身做充分的展开。

因此如果直接定义为#define _STR(x) #x的话,在展开的时候__LINE__直接被当成“__LINE__”了,而无法得到当前的行号“33”。

而如上定义的话,根据前面所说的C语言宏展开的规则,会对编译器定义的特殊的宏__LINE__作充分的展开得到其表示的含义——行号“33”后,

再传给_VAL(x)进一步展开,从而才能得到正确的结果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息