宏函数:
#define 宏名(a,b,c,...) a+b*c
宏函数不是真正的函数,而是带参数的宏,只是使用方法像函数而已。
在代码中使用宏函数,预处理时会经历两次替换,第一次把宏函数替换成它后面的一串代码、表达式,第二次把宏函数中的参数替换到表达式中。
如果宏函数后面的代码有多行,可以使用大括号包括,进行保护。
#define 宏名(a,b,c,...) {代码1; 代码2; ...}
宏函数后面的代码不能直接换行,如果代码确定太长,可以使用续行符换行。
#define 宏名(a,b,c,...) { \
代码1; \
代码2; \
... \
}
普通函数与宏函数的优缺点:
宏函数的优点:
1、执行速度快,它不是真正的函数调用,而是代码替换,不会经历传参、跳转、
返回值。
2、不会检查参数的类型,因此通用性强。
宏函数的缺点:
1、由于它不是真正的函数调用,而是代码替换,每使用一次,就会替换出一份代码,会造成代码冗余、编译速度慢、可执行文件变大。
2、没有返回值,最多可以有个执行结果。
3、类型检查不严格,安全性低。
4、无法进行递归调用。
函数的优点:
1、不存在代码冗余的情况,函数的代码只会在代码段中存储一份,使用时跳转过去执行,执行结束后再返回,还可以附加返回值。
2、安全性高,会对参数进行类型检查。
3、可以进行递归调用,实现分治算法。
函数的缺点:
1、相比宏函数它的执行速度慢,调用时会经历传参、跳转、返回等过程,该过程耗费大量的时间。
2、类型专用,形参什么类型,实参必须是什么类型,无法通用。
宏函数如何使用:
什么样的代码适合封装成宏函数?
1、代码量少,即使多次使用也不会造成代码段过度冗余。
2、调用次数,但执行次数多。
3、对返回值没有要求。
设计宏时要注意的问题:
1、末尾不要加分号。
2、多加小括号防止产生二义性。
3、不要使用自加、自减的变量给宏函数提供参数。
封装一个malloc、free函数
my_malloc 它要记录my_malloc的调用位置,申请到的内存地址
my_free 它要记录my_free的调用位置,释放到的内存地址
void* _my_malloc(size_t size,const char* file,const char* func,size_t line) { void* ptr = malloc(size); printf("%s %s %d 申请了%d字节的内存,地址是%p\n",file,func,line,size,ptr); return ptr; } // 由于my_malloc必须有返回值,所以只能使用这种方式中转一下 #define my_malloc(size) _my_malloc(size,__FILE__,__func__,__LINE__) #define my_free(ptr) {\ free(ptr);\ printf("%s %s %d 释放了内存 %p\n",__FILE__,__func__,__LINE__,ptr);\ }