分析c语言函数的优缺点,C/C ——浅谈函数宏应用优缺点

本文讨论了老一辈C语言程序员倾向于使用宏来提高执行效率的现象,但指出在现代编译器和硬件环境下,函数宏的性能优势已不明显,且存在多重求值等潜在问题。作者建议避免使用函数宏,尤其是在C++和Java中,推荐使用在线函数。文章还给出了宏使用不当导致的错误示例,并强调了正确使用括号的重要性,以防止意外的运算顺序导致的错误。总结来说,应谨慎使用宏,优先选择安全的函数实现。
摘要由CSDN通过智能技术生成

老的C语言程序员中有一种倾向,就是把很短的执行频繁的计算写成宏,而不是定义为函数。完成I / O的g e t c h a r,做字符测试的i s d i g i t都是得到官方认可的例子。人们这样做最根本的理由就是执行效率:宏可以避免函数调用的开销。实际上,即使是在C语言刚诞生时(那时的机器非常慢,函数调用的开销也特别大),这个论据也是很脆弱的,到今天它就更无足轻重了。有了新型的机器和编译程序,函数宏的缺点就远远超过它能带来的好处。

避免函数宏。在C++ 里,在线函数更削减了函数宏的用武之地,在J a v a里根本就没有宏这种东西。即使是在C语言里,它们带来的麻烦也比解决的问题更多。

函数宏最常见的一个严重问题是:如果一个参数在定义中出现多次,它就可能被多次求

值。如果调用时的实际参数带有副作用,结果就会产生一个难以捉摸的错误。下面的代码段

来自某个,其意图是实现一种字符测试:

#define isupper(c) ((C) >=’A’ && (C) <=’Z’)

请注意,参数c在宏的体里出现了两次。如果i s u p p e r在下面的上下文中调用:

While (isupper(C=getchar()))

那么,每当遇到一个大于等于A的字符,程序就会将它丢掉,而下一个字符将被读入并去与Z

做比较。C语言标准是仔细写出的,它允许将i s u p p e r及类似函数定义为宏,但要求保证它

们的参数只求值一次。因此,上面的实现是错误的。

直接使用c t y p e提供的函数总比自己实现它们更好。如果希望更安全些,那么就一定不

要嵌套地使用像g e t c h a r这种带有副作用的函数。我们重写上面的测试,把一个表达式改成

两个,这里还为捕捉文件结束留下机会:

While ((C = getchar()) != EOF && isupper(C))

有时多次求值带来的是执行效率问题,而不是真正的错误。考虑下面这个例子:

#define ROUND_TO_INT(x) ((int) ((X) +(((X)>0)?0.5:- 0.5)))

Size= ROUND_TO_INT(sqrt(dx*dx+dy*dy))

这种写法使平方根函数的计算次数比实际需要多了一倍。甚至对于很简单的实际参数,像

R O U N D T O I N T体这样的复杂表达式也会转换成许多指令。这里确实应该把它改成一个函数,

在需要时调用。宏将在它每次被调用的地方进行实例化,结果会导致被编译的程序变大( C + +

的在线函数也存在这个缺点)。

给宏的体和参数都加上括号。如果你真的要使用函数宏,那么请特别小心。宏是通过文本替

换方式实现的:定义体里的参数被调用的实际参数替换,得到的结果再作为文本去替换原来

的调用段。这种做法与函数不同,常给人带来一些麻烦。假如square是个函数,表达式:

1/ square(x)

的工作将很正常。而如果它的定义如下:

#define square(x) (x)*(x)

上面表达式将被展开成一个错误的内容:

1/(x)*(x)

这个宏应该定义为:

#define square(X) ((x)*(x))

这里所有的括号都是必需的。即使是在宏定义里完全加上括号,也不可能解决前面所说的多

次求值问题。所以,如果一个操作比较复杂,或者它很具一般性,值得包装起来,那么还是

应该使用函数。

C++ 提供的在线函数既避免了语法方面的麻烦,而且又可得到宏能够提供的执行效率,

很适合用来定义那些设置或者提取一个值的短小函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值