宏与函数

来源:互联网 发布:儿童学编程 软件 编辑:程序博客网 时间:2024/06/05 07:26

一:#define
首先,我们来看一个例子:
#define name stuff//预处理器在出现name时候回替换为stuff。
#define
1>#define SQUARE(x)    x*x
a=5;
printf("%d\n",SQUARE(a+1));
SQUARE(a+1);//预期是多少呢?预期是36,结果是11!
为什么呢?
首先,我们来看看这个SQUARE(a+1)替换了之后会是什么?
5+1*5+1!刚好是11!
所以我们得出了结论:必须定义为#define SQUARE(x)  (x)*(x)!
于是我们接着看:
2>#define DOUBLE(x)    (x)+(x)
a=5;
printf("%d\n",10*DOUBLE(a));//预期是多少呢?预期是100,可是实际结果是55!
为什么呢?
我们来看这个10*DOUBLE(a)-->为10*(a)+(a)=10*5+5=55

所以,对于数值表达式进行求值的宏定义都应该加上括号。
3>#define repeat do
    #define until(x)  while(!(x))//则为:repeat{
                                                                           statements
                                                                       }while(!(i>=10));//i>=10两边的括号用于确保在!操作符执行之前先完成这个表达式的求值。
 二:#define替换
1>在调用宏的时候,首先对参数进行检查,看是否包含有任何由#define定义的符号。如果是,首先被替换。
2>替换文本随后就被插入到程序中原来的文本位置。对于宏,函数名被值替换。
3>最后,再次对结果进行扫描,看它是否包含#define,若有,重复2>。
---》宏函数和#define定义可以包含其他的#define定义的符号,但是宏
不可以递归!

将宏函数插入到字符串常量中,可以使用:
(1)邻近字符串自动链接
#define print(format,value)
printf("the value is "format"\n",value)
print("%d",(x+3));//这种技巧只有字符串常量为宏参数时候才可以使用
(2)使用预处理器将宏参数转为一个字符串
#define print(format,value)
printf("the value of"value" is "format"\n",value);
print("%d",x+3);
三:宏与函数,宏与内联函数
1:宏与函数:
(1)宏用于执行简单的计算。不用函数是因为调用和从函数返回的代码很可能比实际这个小型计算机工作代码更大。
(2)函数参数必须说明一种特定的类型。所以它只能在类型合适的表达式中被使用,宏可以用于任何可以用>比较的类型,宏与类型无关。

使用宏的不利之处:每次使用宏,一份宏定义代码的拷贝都将插入到程序里面。
#define MALLOC(n,type)      ((type *)malloc((n)*sizeof(type)))
第一句---->第二句(通过预处理器)
pi=MALLOC(25,int)-------->pi=((int *)malloc((25)*sizeof(int)));
2:宏与内联函数:
  函数必须要将程序执行的顺序转移到函数所存放在内存中的某个地址,将函数的程序内容执行完后,再返回到专区执行该函数前的地方,这种转移操作要求在转去执行前保存现场并且记忆执行的现场,转会后回复现场,函数调用要有一定的时间和空间方面的开销,也必将影响其效率。而宏只是在预处理的地方把代码展开,不许要额外的空间和时间开销。
宏是预处理器对宏进行替代,预处理器处在的关键问题使得我们可以认为预处理器的行为和编译器的行为。

四:带副作用的宏参数


当宏参数在宏定义中出现的次数超过一次的时候,如果这个参数具有副作用,那么你使用这个宏的时候,就可能出现危险,副作用就是在表达式中出现的永久性结果
(1)#define   MAX(a,b)    ((a)>(b)?(a):(b))
x=5;
y=8;
z=MAX(x++,y++);//替换:(x++)>(y++)?(x++):(y++)
6>9?(x++):(y++)//这句话在执行的时候,由于6是小于9的,所以"x++”这句话就不会执行,直接将y的值赋给z之后,再执行个"y++ " 
所以有printf("x=%d,y=%d,z=%d\n",x,y,z);
(2)getchar()也具有副作用,调用这个函数将“消耗”输入字符,那么就不能重复调用这个函数

 #define宏   与  函数
代码长度
宏:每次使用宏,宏代码都被插入到程序中,除了非常小的宏之外,程序代码大幅度增加
函数:函数代码出现在一个地方,每次使用这个函数的时候,都会调用那个地方同一份代码
执行速度
宏:更快
函数:存在函数调用/返回的额外开销
操作符优先级
宏:宏参数的求值是在所有周围表达式的上下文环境里,除非他们加上括号,否则临近操作符的优先级可能会产上不可预料的结果
函数: 函数参数只在函数调用时求值一次,它的结果值传递给函数。表达值的求值结果更容易预测
参数求值
宏: 参数每次用于宏定义的时候,都会重新求值,由于多次求值,具有副作用的参数可能会产生不可预料的结果
函数: 参数在函数被调用前只求值一次,在函数中多次使用并不会导致多种求值过程,没参数副作用并没有任何特殊问题