函数(C语言的核心)
专题六:函数(C语言的核心)。包括以下章节:
- 认清函数的真面目
- 可变参数列表
- 李逵和李鬼
- 函数调用行为
- 函数递归详解
- 函数设计技巧
李逵 VS 李鬼
3-1.c
#include <stdio.h>
#define RESET(p, len) while( len > 0) ((char*)p)[--len] = 0
void reset(void* p, int len)
{
while( len > 0 )
{
//p[--len] ==> *(p+(--len))
//p指向的空间每个字节都设为0
((char*)p)[--len] = 0;
}
}
int main()
{
int array[] = {1, 2, 3, 4, 5};
int len = sizeof(array);
int i = 0;
for (i = 0; i < 5; i++) {
printf("%d\n", array[i]);
}
// reset(array, len);
RESET(array, len);
for (i = 0; i < 5; i++) {
printf("%d\n", array[i]);
}
return 0;
}
函数 VS 宏
- 宏是由预处理直接替换展开的,编译器不知道宏的存在
- 函数是由编译器直接编译的实体,调用行为由编译器决定
- 多次使用宏会导致程序代码量增加
- 函数是跳转执行的,因此代码量不会增加
- 宏的效率比函数要高,因为是直接展开,无调用开销
- 函数调用时会创建活动记录,效率不如宏
宏的优点和缺点
宏的效率比函数稍高,但是其副作用巨大,容易出错
3-2.c
#include <stdio.h>
#define ADD(a, b) a + b
#define MUL(a, b) a * b
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
int main()
{
int i = 1;
int j = 10;
//直接展开:printf("%d\n", 1+2*3+4),不是我们想要的结果
printf("%d\n", MUL(ADD(1, 2), ADD(3, 4)));
//直接展开:printf("%d\n", ((i++) < (j) ? (i++) : (j)))
//((i++) < (j) ? (i++) : (j)) "?:"是顺序点,"?"之前计算一次i=2,所以printf("%d\n", i++)打印是2
printf("%d\n", _MIN_(i++, j));
return 0;
}
结果:
函数优点和缺点
函数存在实参到形参的传递,因此无任何副作用;但是函数需要建立活动对象,效率受影响
3-3.c
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int mul(int a, int b)
{
return a * b;
}
int _min_(int a, int b)
{
return a < b ? a : b;
}
int main()
{
int i = 1;
int j = 10;
printf("%d\n", mul(add(1, 2), add(3, 4)));
printf("%d\n", _min_(i++, j));
return 0;
}
结果:
宏无可替代的优势
宏参数可以是任何C语言实体
- 宏编写的MIN参数类型可以是int, float等等
- 宏的参数可以是类型名
3-4.c
#include <stdio.h>
#include <malloc.h>
#define MALLOC(type, n) (type*)malloc(n * sizeof(type))
int main()
{ //而函数不可能传递int(类型名)参数
int* p = MALLOC(int, 5);
int i = 0;
for(i=0; i<5; i++)
{
p[i] = i + 1;
printf("%d\n", p[i]);
}
free(p);
return 0;
}
小结
- 宏和函数并不是竞争对手
- 宏能够接受任何类型的参数,效率高,易出错
- 函数的参数必须是固定类型,效率稍低,不易出错
- 宏可以实现函数不能实现的功能