【C语言】宏定义的一些所见所闻和心得

来源:互联网 发布:struts2源码分析 pdf 编辑:程序博客网 时间:2024/05/15 07:27

系统型程序会采用很多的宏定义,写的精髓的宏可以大大加强代码的可读性精简代码量,多的了解宏也比较容易去了解系统级的代码。

1、宏定义

#define <宏名>[(宏参数)] <内容串> //[]为可选项

define的作用是字符串替代,替代时机是程序处理完include之后由预处理器做字符串替代(GCC预处理器代码研究ing)。在预处理器处理define的时候只进行对应的展开和替换,不会进行任何的计算,这是最基本的原则。所谓“替换”举例如下:#define plus 1+1,程序中如果有plus*plus,我们预期得到结果4,结果得到结果为3,原因是替换"plus*plus"为“1+1*1+1”。

    宏的意义:1、方便修改维护;2、提高程序效率。举例:程序中大量使用π,定义

#define PI 3.14

提高效率在于带参宏替代功能较少的函数非常使用且高效,比如一个10^n的循环中每次都有一次取MAX的操作,宏定义的MAX效率大大强于函数。

    宏的特别语法:参数是不能带引号的,也就是说

#define cat("a","b") printf("ab"); 

无法表示传两个字符串参数并且连起来输出,应该使用#,如:
#define cat(a,b) printf(#a#b);

这样在使用的时候cat(lo,ve)则输出love字符串。

这样可以得到a1,a2,a3...a100的变量的值(当然你得先声明他们);同样可以
for(int i = 1; i <= 100; i ++){    fopen(cat(a,i),"r");    ...    fclose(cat(a,i));}
这样你可以得到一系列文件的操作,还是相当实用的。

接着是/的用法

#define SWAP(t,x,y) \{\t temp = *y;\*y = *x;\*x = temp;\}
这里的反斜杠\作用在于表示这里虽然换行但是实际也是宏的一部分(注意反斜杠后面直接回车不能有空格什么的),用来定义一些程序块很方便,这里有点类似C++的模板。


2常用宏

一下就收了一些常用的宏,有些实用有些有趣。

#findef XXX

#define XXX

//这里一般写.h的时候要用,防止重复定义

#define FPOS( type, field ) ( (size_t) &(( type *) 0)-> field )

//这个是求某个域在某个结构中的偏移,在下觉得这个在struct中用比较好,如

strcut node{    int val;    node *next;};printf("off of val=%d",FPOS(node,val));printf("off of next=%d",FPOS(node,next));
上面两个输出分别是0和4,。这里解释下这个宏的原理,size_t是32位无符号数,stddef.h中有
typedef unsigned int size_t;                      /*mine is 32bit machine*/
然后0是指地址为0,合起来就是把地址0强制转换成type类型,然后找他的field域的地址并转换成size_t输出来,也就是输出field的首地址。这个利用0地址相当赞!

还有一些位掩码的宏比较容易构造比如取低八位和取高八位:

#define LL(num) num&255
#define HH(num) num&0xFF00
还有宏之间的相互嵌套,这里给出别人博客上的描述:(点击打开链接)

二、 当宏参数是另一个宏的时候 需要注意的是凡 宏定义里有用''#''或''##''的地 方宏参数是不会再展开. 1, 非''#''和''##''的情况 #define TOW      (2) #define MUL(a,b) (a*b) printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW)); 这行的宏会被展开为: printf("%d*%d=%d\n", (2), (2), ((2)*(2))); MUL里的参数TOW会被展开为(2). 2, 当有''#''或''##''的时候 #define A          (2) #define STR(s)     #s #define CONS(a,b)  int(a##e##b) printf("int max: %s\n",  STR(INT_MAX));    // INT_MAX #include<climits> 这行会被展开为: printf("int max: %s\n", "INT_MAX"); printf("%s\n", CONS(A, A));               // compile error  这 一行则是: printf("%s\n", int(AeA)); INT_MAX和A都 不会再被展开, 然而解决这个问题的方法很简单. 加 多一层中间转换宏. 加这层宏的用意是把所 有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就 能得到正确的宏参数. #define A           (2) #define _STR(s)     #s #define STR(s)      _STR(s)          // 转 换宏 #define _CONS(a,b)  int(a##e##b) #define CONS(a,b)   _CONS(a,b)       // 转 换宏 printf("int max: %s\n", STR(INT_MAX));          // INT_MAX,int型的最大值,为一个变量 #include<climits> 输出为: int max: 0x7fffffff STR(INT_MAX) -->  _STR(0x7fffffff) 然 后再转换成字符串; printf("%d\n", CONS(A, A)); 输 出为:200 CONS(A, A)  -->  _CONS((2), (2))  --> int((2)e(2)) 三、''#''和''##''的一些应用特例 1、合并匿名变量名 #define  ___ANONYMOUS1(type, var, line)  type  var##line #define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line) #define  ANONYMOUS(type)  __ANONYMOUS0(type, __LINE__) 例:ANONYMOUS(static int);  即: static int _anonymous70;  70表 示该行行号; 第一层:ANONYMOUS(static int);  -->  __ANONYMOUS0(static int, __LINE__); 第二层:                        -->  ___ANONYMOUS1(static int, _anonymous, 70); 第三层:                        -->  static int  _anonymous70; 即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开; 2、填充结构 #define  FILL(a)   {a, #a} enum IDD{OPEN, CLOSE}; typedef struct MSG{   IDD id;   const char * msg; }MSG; MSG _msg[] = {FILL(OPEN), FILL(CLOSE)}; 相当 于: MSG _msg[] = {{OPEN, "OPEN"},               {CLOSE, "CLOSE"}}; 3、记录文件名 #define  _GET_FILE_NAME(f)   #f #define  GET_FILE_NAME(f)    _GET_FILE_NAME(f) static char  FILE_NAME[] = GET_FILE_NAME(__FILE__); 4、 得到一个数值类型所对应的字符串缓冲大小 #define  _TYPE_BUF_SIZE(type)  sizeof #type #define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type) char  buf[TYPE_BUF_SIZE(INT_MAX)];      -->  char  buf[_TYPE_BUF_SIZE(0x7fffffff)];      -->  char  buf[sizeof "0x7fffffff"]; 这里相当于: char  buf[11];  

先学到这里了,明天看能不能找出处理#define的源码,这一部分肯定有很强大的coding技巧在里面^ ^





原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 汽车买贵了2万多怎么办 宝宝眼皮被蚊子咬肿了怎么办 一岁宝宝撞头咬到舌头有伤口怎么办 二胎快生了老大特别粘人怎么办 生二胎不舍得大宝跟奶奶睡怎么办 怀二胎婆婆不帮忙带孩子怎么办 注册过的高铁用户名忘了怎么办 硕士延期毕业找好的工作怎么办 竞彩足球绑定信用卡提不了现怎么办 qq启动出现问题请卸载重装怎么办 u盘有文件打开后却是空的怎么办 王者荣耀不记得所在的区服怎么办 交易猫出售游戏账号是微信号怎么办 网银密码输错3次怎么办 无线网卡信号很好就是没网速怎么办 红米2a忘了登陆账号怎么办 qq封了密保手机没用了怎么办 乐视手机重置账号密码忘了怎么办 此版本的ios不支持银联怎么办 单反m档拍出来照片是黑色怎么办 从兴趣部落老发骚扰信息怎么办 在厂里辞一个月厂长不批怎么办 在厂里做管理被员工恐吓怎么办 在葡京娱乐输了很多钱怎么办 从珠海入镜澳门北京往返签注怎么办 艾艾灸灸了一身小子子怎么办? 微信视频已过期或已清理怎么办 视频已过期或已被清理怎么办 小孩作业不会老婆天天吵骂打怎么办 苹果手机在太阳下屏幕变暗怎么办 斗鱼的鱼丸竞猜主播结算了怎么办 附近有个小姐姐想加她好友怎么办 孩子出现听别人说话语速很快怎么办 苹果手机上的邮件删了怎么办 手机qq邮箱独立密码忘记了怎么办 哺乳期吃了人参回奶了怎么办? 扣扣邮箱里的邮件过期了怎么办 一体机的管理员账号被删除了怎么办 手机里的邮箱重要吗删除了怎么办 华为荣耀10账号邮箱忘记了怎么办 大陆微信号在台湾登录不上怎么办