文档章节

【原创】Stringification 在二级宏定义中的使用

摩云飞
 摩云飞
发布于 2013/04/28 13:39
字数 771
阅读 413
收藏 1

        最近在研究 Redis-2.6.12 的源码时,重新对一处宏展开的用法进行了梳理,记录如下:

在 zmalloc.h 中有如下定义,
/* Double expansion needed for stringification of macro values. */
#define __xstr(s) __str(s)
#define __str(s) #s
       在注释中出现了一个专有名词“ stringification ”,经查阅,网络上比较认可的翻译是“字符串化”。所以上面双重宏定义的用途为“用于宏值字符串化的双重宏展开 ”。这个概念似乎比较模糊,无法让我深刻理解其用意,幸好有下面的 资料
3.4 Stringification

Sometimes you may want to convert a macro argument into a string constant. Parameters are not replaced inside 
string constants, but you can use the ‘#’ preprocessing operator instead. When a macro parameter is used with 
a leading ‘#’, the preprocessor replaces it with the literal text of the actual argument, converted to a string 
constant. Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification.

There is no way to combine an argument with surrounding text and stringify it all together. Instead, you can 
write a series of adjacent string constants and stringified arguments. The preprocessor will replace the 
stringified arguments with string constants. The C compiler will then combine all the adjacent string constants 
into one long string.

Here is an example of a macro definition that uses stringification:

     #define WARN_IF(EXP) \
     do { if (EXP) \
             fprintf (stderr, "Warning: " #EXP "\n"); } \
     while (0)
     WARN_IF (x == 0);
          ==> do { if (x == 0)
                fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);
The argument for EXP is substituted once, as-is, into the if statement, and once, stringified, into the argument 
to fprintf. If x were a macro, it would be expanded in the if statement, but not in the string.

The do and while (0) are a kludge to make it possible to write WARN_IF (arg);, which the resemblance of WARN_IF 
to a function would make C programmers want to do; see Swallowing the Semicolon.

Stringification in C involves more than putting double-quote characters around the fragment. The preprocessor 
backslash-escapes the quotes surrounding embedded string constants, and all backslashes within string and character 
constants, in order to get a valid C string constant with the proper contents. Thus, stringifying p = "foo\n"; 
results in "p = \"foo\\n\";". However, backslashes that are not inside string or character constants are not 
duplicated: ‘\n’ by itself stringifies to "\n".

All leading and trailing whitespace in text being stringified is ignored. Any sequence of whitespace in the middle 
of the text is converted to a single space in the stringified result. Comments are replaced by whitespace long before
 stringification happens, so they never appear in stringified text.

There is no way to convert a macro argument into a character constant.

If you want to stringify the result of expansion of a macro argument, you have to use two levels of macros.

     #define xstr(s) str(s)
     #define str(s) #s
     #define foo 4
     str (foo)
          ==> "foo"
     xstr (foo)
          ==> xstr (4)
          ==> str (4)
          ==> "4"
s is stringified when it is used in str, so it is not macro-expanded first. But s is an ordinary argument 
to xstr, so it is completely macro-expanded before xstr itself is expanded (see Argument Prescan). Therefore, 
by the time str gets to its argument, it has already been macro-expanded.
      内容有点长,但确实是对  Stringification 作出了全面的解释。其中也对双重宏定义的用法进行了举例说明。针对 xstr(foo) 展开的情况,由于 xstr() 本身是一个符合普通宏展开定义的东东,而 foo 同样是这样的一个东东 ,所以,在对  xstr(foo) 进行宏展开的时,会按照正常的展开顺序进行,即先展开 foo,再展开 xstr 。

      至于采用二级宏定义的好处,当然就是可以更加灵活的对宏展开时的内容进行控制


© 著作权归作者所有

共有 人打赏支持
摩云飞
粉丝 368
博文 534
码字总数 952694
作品 0
徐汇
程序员
私信 提问
关于C语言中的连接符的用法 # ## macro stringize

首先面向需求,小工程、代码不多、版本还挺多... 打算用宏控制开关选项、然后通过一长串 if elif ... endif 来控制生成版本号、而且还要根据兼容性跟细小变更做三级版本号.... 所以就需要一个...

卜霞森
2015/09/24
422
1
iOS学习之UIPickerView控件的关联选择

接上篇iOS学习之UIPickerView控件的简单使用 接着上篇的代码 http://download.csdn.net/detail/totogo2010/4391870 ,我们要实现的效果如下: 当选择左边的一级选项时,左边展示一级选项里含...

知行合一100
2012/06/25
0
0
EOSIO 智能合约数据库演练

前几天翻译了一篇关于EOS智能合约数据库的内容,今天来演示一下数据库的使用方法。 目录 增 查 改 删 新增 新增内容往往用到构造函数,来进行数据库对象的新增。 .cpp 所有的智能合约都继承自...

tclabs
05/17
0
0
浅析linux中的宏contianer_of

container_of是linux中的一个宏,它的作用是通过结构体中某一成员的地址来获得该成员所在结构体的地址。其定义在include/linux/kernel.h中653行,如下所示: 下面对上述代码进行简单的介绍:...

拾月彷徨
2011/09/26
0
0
普中PZ6806开发板 STM32学习笔记2 使用库函数点亮一个LED

版权声明:(谢厂节的博客)博主文章绝大部分非原创,转载望留链接。 https://blog.csdn.net/xundh/article/details/84404561 代码结构: 说明 : 开发板的LED接在GPIOC的Pin0-Pin7 led 头文...

谢厂节
11/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

linux脚本中父shell与子shell 执行的几种方式

本文主要介绍以下几个命令的区别: shell subshell source $ (commond) `commond` Linux执行Scripts有两种方式,主要区别在于是否建立subshell 1. source filename or . filename 不创建sub...

问题终结者
16分钟前
1
0
安装jdk和Tomcat

12月12日任务 16.1 Tomcat介绍 16.2 安装jdk 16.3 安装Tomcat Tomcat介绍 Tomcat是apache软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项目,由apache、Sun和其他一些...

robertt15
17分钟前
3
0
Beetl 免费视频

来自 https://my.oschina.net/gking?q=Beetl ,Beetl终于有人录制视频了 项目git地址:https://gitee.com/gavink/beetl-blog 视频地址:下载下来会更清晰,视频比较长,可使用倍速看 百度网盘...

闲大赋
29分钟前
0
0
isEmpty和null的区别

isEmpty和null的区别: 1.一个是对象为空(IsNull),一个是值为空(IsEmpty) 2.IsNull指任务类型变量是否为空包括对象类型的变量。 IsNull函数: 功能:返回Boolean的值,指明表达是否不包...

DemonsI
56分钟前
3
0
Centos7 安装mysql与php

https://blog.csdn.net/qq_36431213/article/details/79576025 官网下载安装mysql-server 依次使用下面三个命令安装 wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.r......

Yao--靠自己
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部