在C程序中,可以用宏代码提高执行效率,宏代码本身不是函数,但使用起来像函数,编译预处理器用拷贝宏代码的方式取代函数调用,省去了参数压栈、生成汇编语言的CALL调用、返回参数、执行return等过程,从而提高了速度。使用宏代码最大的缺点是容易出错,预处理在拷贝宏代码时常常产生生意想不到的边际效应。例如:
#define MAX(a,b) (a)>(b)?(a):(b)
语句:
Result=MAX(i,j)+2;
将被预处理器扩展为:
Result=(i)>(j)?(i):(j)+2;
由于运算符”+”比运算符”?:”的优先级高,所以上述语句并不等价于期望的:
Result=(i)>(j)?(i):(j)+2;
如果把宏代码改写为:
#defineMAX(a,b)(a)>(b)?(a):(b)
则可以解决由优先级引起的错误,但是即使使用修改后的宏代码也不是万无一失的。
例如语句:
Result=MAX(i++,j);
将被预处理器解释为:
Result=(i++)?(j)?(i++)(j); //在不同一个表达式中i被两次求值
宏的另一个缺点就是不可调试,但是内联函数是可以调试的。内联函数不是也像宏一样进行代码展开吗?其实内联函数的可调试不是说它展开后还能调试,而是在程序的调试版本里它根本就没有真正内联,编译器像普通函数那样为它生成含有调试信息可执行代码。在程序的发行版本里,编译器才会实施真正的内联。有的编译器可以设置函数内联开关。例如Visual C++。
对于C++而言,使用宏代码还是另一种缺点:无法操作累的私有数据成员。
对任何内联函数,编译器在符号表里放入函数的声明,包括名字。参数类型,返回值类型。如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里。在调用一个内联函数时,编译器首先检查调用是否正确,如果正确,内联函数的代码就会直接替换函数调用语句,于是省去了函数调用的开销,这个过程与预处理器有显著的不同,因为预处理器不能进行类型安全检查和自动类型转换,假如内联函数是成员函数,对象的地址会被放在合适的地方,这也是预处理器办不到的。
转载:http://www.lirenedu.org/index.php?ack=xinwen&id=1159