[C] 宏的一些高级用法
前言
非常感谢monkey_zx整理的#define命令的一些高级使用,本文主要对他的这篇文章做些补充,加深对部分宏的原理和用法的理解。
特殊符号
(1)#,表示将跟在它之后的参数转换为字符串。
例子:
#define STR(x) #x
如:STR(amigo)等价"amigo"。
(2)##,表示先分隔,然后强制连接前后两个参数。
例子:
#define VAR_NAME(type, name) type type##_##name #define VAR_NAME1(type, name) type type##_name##name
如:
VAR_NAME(int, a)等价于「int int_a」(即定义名为int_a的int变量)。先分隔成type、_、name,之后替换,最后再连接起来。
VAR_NAME1(int, b)等价于“「int int_nameb」”。先分隔成type、_name(这里面的name之后是不会被替换的)、name,之后替换,最后在连接起来。
(3)#@,转为字符。如果后面的字符为2-4,则返回最后一个字符,编译时会有“截断常量值”的警告。如果字符数大于4个,则编译时会有“常量中的字符太多”的错误。
例子:
#define CHAR(x) #@x
如:
CHAR(1)等价于'1'(const char)。
CHAR(abc)等价于'c'(const char)。
一些常用的宏
(1)do{...}while(0) 作用详见:http://kernelnewbies.org/FAQ/DoWhile0
例子:
#include <stdlib.h> #include <errno.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0)
(2)得到一个field在结构体(struct)中的偏移量
#define OFFSETOF( type, field ) ( (size_t) &(( type *) 0)-> field )
解释:
- (type *)0:把0地址当成type类型的指针。
- ((type *)0)->field:对应域的变量。
- &((type *)0)->field:取该变量的地址,其实就等于该域相对于0地址的偏移量。
- (size_t)&(((type *)0)->field):将该地址(偏移量)转化为size_t型数据。
其实还有一种方式得到一个field在结构体(struct)中的偏移量:
#define OFFSETOF(type, field) ( (size_t) ((char *)&((type *)0)->field - (char *)(type *)0) )
(3)较为严谨的min(x, y)与max(x, y)的写法
#define min(x, y) ({ \ typeof(x) _min1 = (x); \ typeof(y) _min2 = (y); \ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) #define max(x, y) ({ \ typeof(x) _max1 = (x); \ typeof(y) _max2 = (y); \ (void) (&_max1 == &_max2); \ _max1 > _max2 ? _max1 : _max2; })
这么写的好处是:当不同类型的参数进行比较时,编译器会提示“warning: comparison of distinct pointer types lacks a cast.”
参考
- http://blog.csdn.net/xiahouzuoxin/article/details/9494503
- http://kernelnewbies.org/FAQ/DoWhile0
- http://blog.163.com/china_2008ay/blog/static/90142252200961971756712/
(完)