Summary
1)#define
是预处理器
处理的单元实体之一,在预编译期进行文本替换
2)#define
定义的宏可以出现在程序的任意地方
,定义之后的代码都可以使用
3)#define
可以定义宏常量,本质上是字面量
4)define
可以定义表达式,使用上类似函数
;功能可能更强大
(类型可以作为参数、求数组大小);更容易出错
(当和其他运算混合在一起时)
5)宏由于是直接文本替换,所以没有任何的调用开销
;宏表达式里不能出现递归
;宏被预处理器处理,所以编译器不知道宏的存在
,自然宏也不会有作用域的概念
,作用域是针对变量和函数的
。
6)常用的预定义宏
宏 | 含义 | 示例 |
__FILE__ |
被编译的文件名 | file1.c |
__LINE__ |
当前行号 | 25 |
__DATE__ |
编译时的日期 | Jan 31 2012 |
__TIME__ |
编译时的时间 | 17:01:01 |
__STDC__ |
编译器是否遵循标准C规范 | 1 |
#define
是预处理器
处理的单元实体之一#define
定义的宏可以出现在程序的任意位置
#define
定义之后的代码都可以使用这个宏1、#define定义的宏常量
#define
定义的宏常量可以直接使用,本质为字面量
(不会占用内存,字符串字面量会存在只读存储区)// test.c中 下面的宏定义正确么?
#define ERROR -1
#define PATH1 "D:\test\test.c"
#define PATH2 D:\test\test.c
#define PATH3 D:\test\
test.cint main()
{
int i = ERROR;
char* p1 = PATH1;
char* p2 = PATH2;
char* p3 = PATH3;
return 0;
}
单步编译
gcc -E test.c -o test.i==> 预编译,生成中间文件.i
gcc -S test.i -o test.s==> 编译,生成汇编文件.s
分析:在第一步预编译阶段,处理define并生成.i文件,这时候不会出错;下一步编译阶段,将中间文件转换为汇编文件时,就会报错。
文章图片
原因在于:在
预编译的阶段,仅仅是做文本替换,没有语法检查
;到了编译阶段,会对替换后的.i文件进行语法检查
,再生成汇编文件,这时候语法检查就出错了。文章图片
2、#define定义的表达式
#define
表达式的使用类似函数调用
#define
表达式可以比函数更强大
#define
表达式比函数更易出错
#define SUM(a, b) (a) + (b)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define DIM(a) sizeof(a) / sizeof(*a)int main()
{
int a = 1;
int b = 3;
int c[2] = {0};
// expected: 4, 1, 2
printf("SUM(a, b) = %d\n", SUM(a, b));
printf("MIN(a, b) = %d\n", MIN(a, b));
printf("size of array = %d\n", DIM(c));
// unexpected: 3
printf("unexpected: %d", MIN(++a, b));
// 期望得到++a和b中的较小的值:2
return 0;
}
分析:
- define表达式
类似
函数调用,像上面的例子中,printf中宏的定义就很像是函数调用。 - define表达式可能
比函数更强大
,如上,DIM宏可以求数组的大小
,但是在C语言中无法通过函数求一个数组的大小
,因为当数组作为函数的参数时,会退化成指针
;再比如,C语言中不能把类型作为参数
,但是宏就可以。 - define表达式
更容易出错
,如上,MIN(++a, b)期望得到的值为2,实际得到的值却是3。由单步编译得到的结果可以看出,替换后的表达式为((++a) < (b) ? (++b) : (b))
,前置的++被执行了2次,所以得到了3。预编译器就像是一个传话筒,在传话的过程中,就发生了歧义
预处理器
处理,编译器并不知道宏的存在;宏表达式用“实参”完全替代形参,
不进行任何运算
;宏表达式
没有任何的调用开销
:(因为直接进行文本替换,不像函数需要参数入栈、返回等开销)宏表达式中不能出现递归定义:(因为宏只在预处理期进行
一次
文本替换,后续的符号编译器就不认识了)#define SUM(n) ((n>0) ? (SUM(n-1) + n) : 0)
int s = SUM(10);
// 编译的时候就会报错,undefined reference SUM
3、宏定义的常量或表达式是否有作用域限制?
下面的程序合法么?
void def()
{
#define PI 3.1415926
#define AREA(r) r*r*PI
}
double area(double r)
{
retrun AREA(r);
}int main()
{
double r = area(10);
return 0;
}
分析:编译、运行都不会出错。说明
宏是没有作用域限制的
。只要定义完,后面的代码都可以用。在定义之前使用就会报错undefined reference。作用域只是针对变量和函数的
,宏在预处理期被展开,在编译期已经没有宏这个东西了
,所以也就没法给宏限定作用域了。4、 常用的预定义宏
宏 | 含义 | 示例 |
__FILE__ |
被编译的文件名 | file1.c |
__LINE__ |
当前行号 | 25 |
__DATE__ |
编译时的日期 | Jan 31 2012 |
__TIME__ |
编译时的时间 | 17:01:01 |
__STDC__ |
编译器是否遵循标准C规范 | 1 |
如有错漏之处,恳请指正。
推荐阅读
- c/c++|有感 Visual Studio 2015 RTM 简介 - 八年后回归 Dot Net,终于迎来了 Mvc 时代,盼走了 Web 窗体时代...
- C/C++|C/C++ basis 02
- Qt实战|Qt+OpenCV联合开发(二十一)--图像翻转与旋转
- Qt实战|Qt+OpenCV联合开发(十四)--图像感兴趣区域(ROI)的提取
- Qt实战|Qt+OpenCV联合开发(十三)--通道分离与合并
- opencv|Qt+OpenCV联合开发(十六)--图像几何形状绘制
- Qt实战|Qt+OpenCV联合开发(十七)--随机数与随机颜色
- SNAT的MASQUERADE地址选择与端口选择
- IPTABLES的连接跟踪与NAT分析
- IPVS分析