设为首页 加入收藏

TOP

C语言预处理命令详解(二)
2015-01-22 21:13:20 来源: 作者: 【 】 浏览:149
Tags:语言 处理 命令 详解
= 25
复制代码
? ? ?本例意在说明,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。
?
? ? ?调用Square函数时,把实参i值传给形参x后自增1,再输出函数值。因此循环5次,输出1~5的平方值。
?
? ? ?调用SQUARE宏时,SQUARE(j++)被代换为((j++)*(j++))。在第一次循环时,表达式中j初值为1,两者相乘的结果为1。相乘后j自增两次变为3,因此表达式中第二次相乘时结果为3*3=9。同理,第三次相乘时结果为5*5=25,并在此次循环后j值变为7,不再满足循环条件,停止循环。
?
? ? ?从以上分析可以看出函数调用和宏调用二者在形式上相似,在本质上是完全不同的。
?
? ? ?带参宏注意事项:
?
宏名和形参表的括号间不能有空格。
宏替换只作替换,不做计算,不做表达式求解。
函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存。
宏的哑实结合不存在类型,也没有类型转换。
函数只有一个返回值,利用宏则可以设法得到多个值。
宏展开使源程序变长,函数调用不会。
宏展开不占用运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)。
为防止无限制递归展开,当宏调用自身时,不再继续展开。如:#define TEST(x) ?(x + TEST(x))被展开为1 + TEST(1)。
2.3 实践用例
? ? ?包括基本用法(及技巧)和特殊用法(#和##等)。
?
? ? ?#define可以定义多条语句,以替代多行的代码,但应注意替换后的形式,避免出错。宏定义在换行时要加上一个反斜杠”\”,而且反斜杠后面直接回车,不能有空格。
?
2.3.1 基本用法
? ? ?1. 定义常量:
?
1 #define PI ? 3.1415926
? ? ?将程序中出现的PI全部换成3.1415926。
?
? ? ?2. 定义表达式:
?
1 #define M ? (y*y+3*y)
? ? ?编码时所有的表达式(y*y+3*y)都可由M代替,而编译时先由预处理程序进行宏替换,即用(y*y+3*y)表达式去置换所有的宏名M,然后再进行编译。
?
? ? ?注意,在宏定义中表达式(y*y+3*y)两边的括号不能少,否则可能会发生错误。如s=3*M+4*M在预处理时经宏展开变为s=3*(y*y+3*y)+4*(y*y+3*y),如果宏定义时不加括号就展开为s=3*y*y+3*y+4*y*y+3*y,显然不符合原意。因此在作宏定义时必须十分注意。应保证在宏替换之后不发生错误。
?
? ? ?3. 得到指定地址上的一个字节或字:
?
1 #define MEM_B(x) ? ? (*((char *)(x)))
2 #define MEM_W(x) ? ? (*((short *)(x)))
? ? ?4. 求最大值和最小值:
?
1 #define MAX(x, y) ? ? (((x) > (y)) ? (x) : (y))
2 #define MIN(x, y) ? ? (((x) < (y)) ? (x) : (y))
? ? ?以后使用MAX (x,y)或MIN (x,y),就可分别得到x和y中较大或较小的数。
?
? ? ?但这种方法存在弊病,例如执行MAX(a++, b)时,a++被执行多少次取决于a和b的大小!所以建议用内联函数而不是这种方法提高速度。不过,虽然存在这样的弊病,但宏定义非常灵活,因为a和b可以是各种数据类型。
?
? ? ?5. 得到一个成员在结构体中的偏移量(lint 545告警表示"&用法值得怀疑",此处抑制该警告):
?
1 #define FPOS( type, field ) \
2 /*lint -e545 */ ((int)&((type *)0)-> field) /*lint +e545 */
? ? ?6. 得到一个结构体中某成员所占用的字节数:
?
1 #define FSIZ(type, field) ? ?sizeof(((type *)0)->field)
? ? ?7. 按照LSB格式把两个字节转化为一个字(word):
?
1 #define FLIPW(arr) ? ? ? ? ?((((short)(arr)[0]) * 256) + (arr)[1])
? ? ?8. 按照LSB格式把一个字(word)转化为两个字节:
?
1 #define FLOPW(arr, val ) \
2 ? ? (arr)[0] = ((val) / 256); \
3 ? ? (arr)[1] = ((val) & 0xFF)
? ? ?9. 得到一个变量的地址:
?
1 #define B_PTR(var) ? ? ? ((char *)(void *)&(var))
2 #define W_PTR(var) ? ? ? ((short *)(void *)&(var))
? ? ?10. 得到一个字(word)的高位和低位字节:
?
1 #define WORD_LO(x) ? ? ? ((char)((short)(x)&0xFF))
2 #define WORD_HI(x) ? ? ? ((char)((short)(x)>>0x8))
? ? ?11. 返回一个比X大的最接近的8的倍数:
?
1 #define RND8(x) ? ? ? ? ? ((((x) + 7) / 8) * 8)
? ? ?12. 将一个字母转换为大写:
?
1 #define UPCASE(c) ? ? ? ? (((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c))
? ? ?13. 判断字符是不是10进值的数字:
?
1 #define ISDEC(c) ? ? ? ? ?((c) >= '0' && (c) <= '9')
? ? ?14. 判断字符是不是16进值的数字:
?
1 #define ISHEX(c) ? ? ? ? ?(((c) >= '0' && (c) <= '9') ||\
2 ? ? ((c) >= 'A' && (c) <= 'F') ||\
3 ? ? ((c) >= 'a' && (c) <= 'f'))
? ? ?15. 防止溢出的一个方法:
?
1 #define INC_SAT(val) ? ? ?(val = ((val)+1 > (val)) ? (val)+1 : (val))
? ? ?16. 返回数组元素的个数:
?
1 #define ARR_SIZE(arr) ? ? (sizeof((arr)) / sizeof((arr[0])))
? ? ?17. 对于IO空间映射在存储空间的结构,输入输出处理:
?
1 #define INP(port) ? ? ? ? ? (*((volatile char *)(port)))
2 #define INPW(port) ? ? ? ? ?(*((volatile short *)(port)))
3 #define INPDW(port) ? ? ? ? (*((volatile int *)(port)))
4 #define OUTP(port, val) ? ? (*((volatile char *)(port)) = ((char)(val)))
5 #define OUTPW(port, val) ? ?(*((volatile short *)(port)) = ((short)(val)))
6 #define OUTPDW(port, val) ? (*((volatile int *)
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 2/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Objective-C中常用的结构体NSRang.. 下一篇编程算法 - 和为s的连续正整数序..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: