[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.

 

参考

 

(完)

posted @ 2014-03-11 21:34  helloamigo  阅读(588)  评论(0编辑  收藏  举报