C语言宏高级用法 [总结]
1、前言
今天看代码时候,遇到一些宏,之前没有见过,感觉挺新鲜。如是上网google一下,顺便总结一下,方便以后学习和运用。C语言程序中广泛的使用宏定义,采用关键字define进行定义,宏只是一种简单的字符串替换,根据是否带参数分为无参和带参。宏的简单应用很容易掌握,今天主要总结一下宏的特殊符号及惯用法。
(1)宏中包含特殊符号:#、##.
(2)宏定义用do{ }while(0)
2、特殊符号#、##
(1)#
When you put a # before an argument in a preprocessor macro, the preprocessor turns that argument into a character array.
在一个宏中的参数前面使用一个#,预处理器会把这个参数转换为一个字符数组
简化理解:#是“字符串化”的意思,出现在宏定义中的#是把跟在后面的参数转换成一个字符串
#define ERROR_LOG(module) fprintf(stderr,"error: "#module"\n")
ERROR_LOG("add"); 转换为 fprintf(stderr,"error: "add"\n");
ERROR_LOG(devied =0); 转换为 fprintf(stderr,"error: devied=0\n");
(2)##
“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。
在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。但是这样做的结果是,被替换段之间存在一些空格。如果我们不希望出现这些空格,就可以通过添加一些##来替代空格。
#define TYPE1(type,name) type name_##type##_type
#define TYPE2(type,name) type name##_##type##_type
TYPE1(int, c); 转换为:int name_int_type ; (因为##号将后面分为 name_ 、type 、 _type三组,替换后强制连接)
TYPE2(int, d);转换为: int d_int_type ; (因为##号将后面分为 name、_、type 、_type四组,替换后强制连接)
3、宏定义中do{ }while(0)
第一眼看到这样的宏时,觉得非常奇怪,为什么要用do……while(0)把宏定义的多条语句括起来?非常想知道这样定义宏的好处是什么,于是google、百度一下了。
采用这种方式是为了防范在使用宏过程中出现错误,主要有如下几点:
(1)空的宏定义避免warning:
#define foo() do{}while(0)
(2)存在一个独立的block,可以用来进行变量定义,进行比较复杂的实现。
(3)如果出现在判断语句过后的宏,这样可以保证作为一个整体来是实现:
#define foo(x) \
action1(); \
action2();
在以下情况下:
if(NULL == pPointer)
foo();
就会出现action1和action2不会同时被执行的情况,而这显然不是程序设计的目的。
(4)以上的第3种情况用单独的{}也可以实现,但是为什么一定要一个do{}while(0)呢,看以下代码:
#define switch(x,y) {int tmp; tmp="x";x=y;y=tmp;}
if(x>y)
switch(x,y);
else //error, parse error before else
otheraction();
在把宏引入代码中,会多出一个分号,从而会报错。这对这一点,可以将if和else语句用{}括起来,可以避免分号错误。
使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低
4、测试程序
简单写个测试程序,加强练习,熟悉一下宏的高级用法。
#include <stdio.h> #define PRINT1(a,b) \
{ \
printf("print a\n"); \
printf("print b\n"); \
} #define PRINT2(a, b) \
do{ \
printf("print a\n"); \
printf("print b\n"); \
}while() #define PRINT(a) \
do{\
printf("%s: %d\n",#a,a);\
printf("%d: %d\n",a,a);\
}while() #define TYPE1(type,name) type name_##type##_type
#define TYPE2(type,name) type name##_##type##_type #define ERROR_LOG(module) fprintf(stderr,"error: "#module"\n") main()
{
int a = ;
int b = ;
TYPE1(int, c);
ERROR_LOG("add");
name_int_type = a;
TYPE2(int, d);
d_int_type = a; PRINT(a);
if (a > b)
{
PRINT1(a, b);
}
else
{
PRINT2(a, b);
}
return ;
}
测试结果如下:

5、参考网址
http://blog.csdn.net/jiangjingui2011/article/details/6706967
http://www.kuqin.com/language/20080721/11906.html
http://www.360doc.com/content/12/0405/16/8302596_201146109.shtml
http://blog.csdn.net/liliangbao/article/details/4163440
C语言宏高级用法 [总结]的更多相关文章
- 【转】C语言宏高级用法 [总结]
1.前言 今天看代码时候,遇到一些宏,之前没有见过,感觉挺新鲜.如是上网google一下,顺便总结一下,方便以后学习和运用.C语言程序中广泛的使用宏定义,采用关键字define进行定义,宏只是一种简 ...
- C语言宏高级用法
1.前言 今天看代码时候,遇到一些宏,之前没有见过,感觉挺新鲜.如是上网google一下,顺便总结一下,方便以后学习和运用.C语言程序中广泛的使用宏定义,采用关键字define进行定义,宏只是一种简 ...
- linux c语言 select函数用法
linux c语言 select函数用法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<unis ...
- jsoup 使用总结4--高级用法之 script js 脚本
jsoup 使用总结4--高级用法之 script js 脚本 大部分时候,我们使用jsoup解析网页的时候,都是直接找到某一类元素,或者按某种selector查询:具体使用方法可以参考jsoup官网 ...
- jsoup 使用总结3--高级用法之 not
jsoup 使用总结3--高级用法之 not 大部分时候,我们使用jsoup解析网页的时候,都是直接找到某一类元素,或者按某种selector查询:具体使用方法可以参考jsoup官网文档 例子代码: ...
- jsoup 使用总结2--高级用法之 :gt(n)
jsoup 使用总结2--高级用法之 :gt(n) 大部分时候,我们使用jsoup解析网页的时候,都是直接找到某一类元素,或者按某种selector查询:具体使用方法可以参考jsoup官网文档 部分h ...
- 9.11 Django关于母版语言的灵活用法
2018-9-11 12:45:38 还是这个连接 : http://www.cnblogs.com/liwenzhou/p/7931828.html 注意: 这节讲的是 母版语言的灵活用法! 可 ...
- 单片机的C语言中位操作用法2
单片机的C语言中位操作用法 在对单处机进行编程的过程中,对位的操作是经常遇到的.C51对位的操控能力是非常强大 的.从这一点上,就可以看出C不光具有高级语言的灵活性,又有低级语言贴近硬件的特点. 这也 ...
- C语言typedef的用法(转)
http://www.cnblogs.com/afarmer/archive/2011/05/05/2038201.html 一.基本概念剖析 int* (*a[5])(int, char*); ...
随机推荐
- malloc()参数为0的情况
问题来自于<程序员面试宝典(第三版)>第12.2节问题9(这里不评价<程序员面试宝典>,就题论题): 下面的代码片段输出是什么?为什么? char *ptr; ))==NULL ...
- 说一说inline-block的奇葩之处
今天本来想聊一下margin和padding,但是当我给div加了一个display:inline-block之后,发现一个问题: .box_demo{border: 1px solid #333;w ...
- 关于C#不同位数相与或,或赋值时,隐藏位数扩展该留意的问题
__int64 a; char b; a = b; a |= b; 如上情况,当b的最高位为1时,即b=0x80(或更大)时,b在扩展成64过程中会将最高位向高位扩展变成0xfffffffffffff ...
- [2015hdu多校联赛补题]hdu5297 Y sequence
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5297 题意:给你一个所有正整数的序列,然后去掉满足x^(2~r)的所有数(x为所有正整数,r>= ...
- node.js 基础学习 express安装使用
安装好nodeJs,我们需要使用命令行中安装express. 我这里默认将Node.js安装在C:\Program Files\nodCejs\盘中. 在保持联网的状态下,依次输入如下命令. npm ...
- Xcode升级插件失效,与添加插件不小心点击Skip Bundle解决办法
一.当发现升级xcode后,插件不能使用,解决办法如下: 1.查看Xcode的UUID 在终端执行 defaults read /Applications/Xcode.app/Contents/Inf ...
- 如何使用JS脚本从HTML中分离图片标签与文本,替换文本中指定的内容并加粗(原创)
var html='ddfsdfsdfdsd dfsdfsdffds<img _src="http://localhost:8490/60E86EA7-FE7B-44BF-8270-4 ...
- 如何编译Less
什么是LESS LESSCSS是一种动态样式语言,属于CSS预处理语言的一种.它编译后就是CSS了,大名鼎鼎的前端框架BootStrap就是用这个语言写的 下面示范下怎么用LESS编译成CSS,尽量简 ...
- js取最小最大值--Math.min()、math.max()
一.Math.min() 返回一组表达式中最小者 eg: var n = Math.min( 2 , 30 ,1 , 200-10 , 300*22 , 20-30 ); alert(n); //打印 ...
- poj3050
#include <stdio.h> #include <set> #include <string> using namespace std; int a[6]; ...