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

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

在 zmalloc.h 中有如下定义, 

?


1

2

3

/* Double expansion needed for stringification of macro values. */

#define __xstr(s) __str(s)

#define __str(s) #s

       在注释中出现了一个专有名词“ stringification ”,经查阅,网络上比较认可的翻译是“字符串化”。所以上面双重宏定义的用途为“用于宏值字符串化的双重宏展开 ”。这个概念似乎比较模糊,无法让我深刻理解其用意,幸好有下面的 资料 : 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

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 。 

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

时间: 2024-10-28 11:17:14

【原创】Stringification 在二级宏定义中的使用的相关文章

宏定义中的##操作符和... and _ _VA_ARGS_ _

1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operator, the ## operator can be used in the replacement section of a function-like macro.Additionally, it can be used in the replacement section of an object-like macro. The ## operator co

C语言可变参数在宏定义中的应用

       在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用可变参数的宏是一个不错的选择. 在C99中规定宏也可以像函数一样带可变的参数,如: #define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__) 其中,...表示可变参数列表,__VA_ARGS__在预处理中,会被实际的参数

OC中的宏 和 C中的预编译宏定义

1.先来几个常用的: [csharp] view plain copy // 是否高清屏   #define isRetina ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 960), [[UIScreen mainScreen] currentMode].size) : NO)   // 是否模拟器   #define isSimulator (

基于C中含有if的宏定义详解_C 语言

含有if的宏定义当宏定义中含有 if 时1) 定义如下宏#define DC(p) if( foo(p) )fun(p)用在下面的环境中if(k>n)DC(k);elseDC(n);宏替换后,如下if(k>n)if( foo(k) )fun(k);elseif( foo(n) )fun( n );可见, 原来的 if 和 else 不再配对.2) 为了避免这类问题, 我们可以将包含if语句的宏定义为一个整体.#define DC(p) {if( foo(p) ) fun(p);}但是, 替换后

c/c++中宏定义##连接符 和#符的使用

C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结.关于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量 通过替换后在其左右各加上一个双引号.比如下面代码中的宏:#define WARN_IF(EXP)    do{ if (EXP)    fprintf(stderr, "Warning: " #EXP &

宏定义的黑魔法 - 宏菜鸟起飞手册

宏定义在C系开发中可以说占有举足轻重的作用.底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行.而在更高层级进行开发时,我们会将更多的重心放在业务逻辑上,似乎对宏的使用和依赖并不多.但是使用宏定义的好处是不言自明的,在节省工作量的同时,代码可读性大大增加.如果想成为一个能写出漂亮优雅代码的开发者,宏定义绝对是必不可少的技能(虽然宏本身可能并不漂亮优雅XD).但是因为宏定义对于很多人来说,并不像业务逻辑那样是每天会接触的东西.即使是能偶尔使

C语言宏定义##连接符和#符的使用

C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结. 关于#和## 在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号.比如下面代码中的宏: #define WARN_IF(EXP) do{ if (EXP) fprintf(stderr, "Warning: " #EXP "

谁能帮我详细讲一下这个宏定义?

问题描述 #defineMAKELONG(a,b)((LONG)(((WORD)(a))|((WORD)(b)))<<16))为什么在涉及底层操作的宏定义中会频繁用到移位操作呢?有什么特殊意义呢?这是MFC类库中的一段代码

函数式宏定义与普通函数的区别_C 语言

在C及C++语言中允许用一个标识符来表示一个字符串,称为宏,该字符串可以是常数.表达式.格式串等.在编译预处理时,对程序中所有出现的"宏名",都用宏定义中的字符串去代换,这称为"宏代换"或"宏展开".宏定义是由源程序中的宏定义命令完成的.宏代换是由预处理程序自动完成的.若字符串是表达式,我们称之为函数式宏定义,那函数式宏定义与普通函数有什么区别呢? 我们以下面两行代码为例,展开描述:函数式宏定义:#define MAX(a,b) ((a)>