注:基础的宏定义注意事项及概念不再赘述。
1、可以在预编译之后的.i文件中查看宏替换之后的代码。
2、可以利用宏定义求数组求数组元素个数。
#define DIM(array) (sizeof(array)/sizeof(*array))
思考:这个功能可以利用函数来实现吗?
int dim(int array[])
{
return sizeof(array)/sizeof(*array);
}
我们在VS2005下对两种方法都进行了实验,利用宏定义的代码如下:
1 #include<stdio.h> 2 3 #define DIM(arr) (sizeof(arr)/sizeof(*arr)) 4 5 int num[]={1,2,4,5,67,78,5}; 6 7 void main() 8 { 9 printf("%d ",DIM(num)); 10 getchar(); 11 }
程序运行结果为7,是正确的。
接下来我们采用函数的方法,看能否实现相同的效果:
1 #include<stdio.h> 2 3 4 5 int num[]={1,2,4,5,67,78,5}; 6 7 int dim(int arr[]) 8 { 9 return sizeof(arr)/sizeof(*arr); 10 } 11 12 void main() 13 { 14 printf("%d ",dim(num)); 15 getchar(); 16 }
实验结果为1,显然这不是我们预期的结果。那么问题出在哪里呢?
这是由于在C语言中,函数的数组参数会退化成一个指针。
这样就可以解释为什么结果为1了,因为在函数中arr是一个指针,在32位系统下,一个指针占4个字节,一个整数也是占4个字节,所以结果为1。
通过这个例子可以说明,宏定义还是有其用武之地的。
3、宏定义与函数的对比:
a、宏定义在预编译期被处理,编译器不知道宏定义的存在。
b、宏表达式用“实参”完全代替形参,不进行任何运算
c、宏表达式没有任何的调用开销
d、宏表达式中不能出现递归的定义。
4、关于#undef,宏定义的常量或者表达式是否有作用域限制?
先来看这样一段代码:
1 #include<stdio.h> 2 3 4 5 int f1(int a,int b) 6 { 7 #define _MIN_(a,b) ((a)<(b)?a:b) 8 return _MIN_(a,b); 9 } 10 11 int f2(int a,int b ,int c) 12 { 13 return _MIN_(_MIN_(a,b),c); 14 } 15 16 void main() 17 { 18 printf("%d ",f1(5,11)); 19 printf("%d ",f2(5,3,2)); 20 getchar(); 21 }
代码运行的结果是5,2,由此我们可以发现,我们在函数f1中定义的宏,在函数f2中还可以使用。
那么假如我们把f2移到f1之前呢?我们这样试了一下,结果编译器报错,说_MIN_未定义在f2中。
这就说明,宏定义的作用域是从它定义之处开始到文件最后都可以使用,那么我们有没有什么办法来限制我们宏定义的作用域呢?这里就用到了我们的#undef关键字。
还是上面的代码,我将f1修改成这样:
1 #include<stdio.h> 2 3 4 5 int f1(int a,int b) 6 { 7 #define _MIN_(a,b) ((a)<(b)?a:b) 8 return _MIN_(a,b); 9 #undef _MIN_ 10 } 11 12 int f2(int a,int b ,int c) 13 { 14 return _MIN_(_MIN_(a,b),c); 15 } 16 17 void main() 18 { 19 printf("%d ",f1(5,11)); 20 printf("%d ",f2(5,3,2)); 21 getchar(); 22 }
编译器同样报错说,在f2中_MIN_未定义,这就说明我们可以通过#undef关键字来人为地限定宏定义的作用域。
5、强大的内置宏:
宏名 意义 示例
_FILE_ 被编译的文件名 file.c
_LINE_ 当前行号 25
_DATE_ 编译时的日期 Jan 31 2012
_TIME_ 编译时的时间 17:01:01
_STDC_ 编译器是否遵循标准C规范 1
我们可以利用上述宏定义打印日志:
#define LOG(s) printf("%s:%d %s ",_FILE_,_LINE_,s)
6、课后思考题:
下面的宏定义是什么意思?宏定义对空格敏感吗?宏“调用”对空格敏感吗?
#define f (x) ((x)-1)