注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

gcc预处理中两个微妙细节问题  

2011-10-20 22:32:29|  分类: Gcc源代码分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

一、字符串化一个标识符

随便举个内核里的例子,其中将一个标识符字符串化的宏定义

linux-2.6.37.1\fs\ceph\super.c

#define _STRINGIFY(x) #x
#define STRINGIFY(x) _STRINGIFY(x)

也就是STRINGIFY将一个标识符转换成字符串,但是这里故弄玄虚的使用了两个宏而不是直接定义其为 #x;这个看起来的确是有些费解,但是这个的确是有其实际意义的--至少是在某些情况下如此。

我们看如果x本身就是一个宏,然后我们定义

#define  GREETING   HELLO

#STRINGIFY(x) #x

printf(STRINGIFY(GREETING));

在这个时候就会发现,此时打印的并不是HELLO,而是GREETING,也就是宏并没有被展开。这说明字符串化操作符#的优先级要高于宏的展开,所以显示如此。但是使用内核定义的版本,那么它打印的就是HELLO,也就是说,这个格式是为了保证输入参数如果是一个宏,那么在宏展开之后再字符串化。

gcc的相关代码gcc-4.1.0\libcpp\macro.c

replace_args (cpp_reader *pfile, cpp_hashnode *node, cpp_macro *macro, macro_arg *args)
函数中,从该函数中可以看到字符串化的判断早于宏的展开。

二、变参函数宏的参数

glibc-2.7\include\libc-symbols.h中一个宏的定义,大家注意,下面attrs宏参数前面有一个连接操作,这里为什么要进行一个没有意义的连接呢?即使不进行连接,也就是为什么要和那个逗号连接这么紧密呢?

# define libm_hidden_proto(name, attrs...) hidden_proto (name, ##attrs)
这个在libm_hidden_proto的参数个数大于等于两个的时候,这个的确是没有意义的,但是如果刚好这个name没有设置attr,也就是我定义的宏为

glibc-2.7\include\math.h

libm_hidden_proto (__expm1l)

大家注意到,这个宏引用的时候只有一个参数,那么之后的attrs就应该展开为空,所以此时应该为

hidden_proto(__expm1l,)

此时可以看到,此时有一个落单的逗号,这明显是一个非法的C语言表达式。但是妙就妙在这个连接符号的引用,正是这个符号的魔幻意义:如果变参展开为空,并且它之前为一个逗号和连接符,那么这个逗号会被预处理自动抹掉。

gcc的相关处理代码同样在replace_args函数中

   else if (src != macro->exp.tokens && (src[-1].flags & PASTE_LEFT))
 {
   count = arg->count, from = arg->first;
   if (dest != first)
     {
       if (dest[-1]->type == CPP_COMMA
    && macro->variadic
    && src->val.arg_no == macro->paramc)
  {
    /* Swallow a pasted comma if from == NULL, otherwise
       drop the paste flag
.  */
    if (from == NULL)
      dest--;
    else
      paste_flag = dest - 1;
  }
       /* Remove the paste flag if the RHS is a placemarker.  */
       else if (count == 0)
  paste_flag = dest - 1;
     }
 

  评论这张
 
阅读(882)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017