在阅读K&R中macro substitution一节中提到
引用
One practical example comes from <stdio.h>, in which getchar and putchar are often defined as macros to avoid the run-time overhead of a
function call per character processed.
在standard input and output一节时,也提到
引用
As we mentioned earlier,"functions" like getchar and putchar in <stdio.h> and tolower in <ctype.h> are often macros, thus avoiding the
overhead of a function call per character.
也就是说使用函数宏可以避免对每个字符都进行函数调用的开销。文中提到的#define也只是起到了文本替换的作用,但没有告知减少开销的原因。想了半天没想明白,后来发现想复杂了,原来这么简单的道理……
用书上的一个例子
#define max(A, B) ((A)>(B)?(A):(B))
x = max(p+q, r+s);
就想#define本身的作用那样,经过preprocessor处理过之后,就成了
x = ((p+q)>(r+s)?(p+q):(r+s));
1、书中也说过,宏定义经过preprocessor做文本上的替换,之后再经过编译器处理,所以函数宏的参数没有类型,因此要自己注意传递参数的类型。
2、真函数调用和函数宏调用编译之后生成的指令也不同。这个很容易理解,至少经过预处理之后的文本含义也不一样。如果max是个真函数,那么在编译之后的代码中调用函数的地方会编译生成传参指令和call指令。如果max是个函数宏,并不会生成传参和call指令,但是每次调用函数宏的地方生成的指令都相当于一个函数体。目标文件相应的也会大许多。
3、宏定义时的书写一定要注意。例如上面例子中的括号是不能省的,这关系到替换之后运算的优先级问题。同样,最外层的括号也不能省,因为赋值运算符的优先级要高一些。省略了最外面的括号,可能在替换之后所表达的意思就截然不一样了。
4、最后一点也是在macro substitution一节中提到的,要注意传递给函数宏的参数是否在执行过程中有多余的运算。上面的例子,max(++a,++b),原意是a、b各自加一次,但是使用函数宏之后的结果是a、b都自加了两次。
分享到:
相关推荐
函数宏,即包含多条语句的宏定义,其通常为某一被频繁调用的功能的语句封装,且不想通过函数方式封装来降低额外的弹栈压栈开销。 函数宏本质上为宏,可以直接进行定义,例如: 复制 #define INT_SWAP(a,b) \ int ...
为了提高程序的效率,我们用define来定义一个函数,这样在频繁调用的时候不会有函数调用的开销了,这是宏函数,但宏函数定义只是把S(a,b)简单地替换成a*b,这样会产生问题,典型的两种: 1.缺括号,比如aera=...
另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类外部...
内联函数与宏本质上是两个不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline。下面详细介绍一下探讨一下内联函数与宏定义。一、内联函数是什么?内联函数是代码被插入到调用者...
内联函数的优越性:一:inline定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换(像宏定义一样展开),没有了调用的开销,效率很高。二:类的内敛函数是一个真正的函数。三:使用内联函数inline...
但是,函数调用也需要一些时间和空间方面的开销,因为调用函数实际上将程序执行流程转移到被调函数中,被调函数的程序代码执行完后,再返回到调用的地方。 这种调用操作要求调用前保护现场并记忆执行的地址,...
C++提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(inline function),又称内嵌函数或内嵌函数。 指定内联函数的方法很...
MATLAB中的内联函数借鉴了C语言中的内联函数,在C语言中,内联函数是通过编译器控制来实现的,它只在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的时间和空间开销。在MATLAB中也...
使用DLL有许多优点:(1)使用DLL的动态连接不是将库代码拷贝,只在程序中记录函数的入口点和接口,在程序执行时才将库代码装入内存,如果有多个程序使用相同的DLL,也只需将DLL在内存中装载一次,节省了内存开销。...
而且qsort要嵌套调用(不嵌套在VB里也慢),我们还要尽量节约堆栈,虽然1M的默认堆栈大小可以被扩充(有相邻的空闲空间时),但是我们依然要考虑可能存在的溢出,所以我做的qsort仅两个参数,两个局部Long型变量。...
介绍内联函数之前,有必要介绍一下预处理宏。内联函数的功能和预处理宏的功能...因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。而宏只是在预处理的地方把代码展开,不需要额外的空间和时间方面的开
4. **减少函数调用开销**: - 减少不必要的函数调用,特别是小型且频繁调用的函数。 - 将关键循环内的函数展开,尤其是在RAM有限的情况下。 5. **优化循环和递归**: - 采用Duff's Device等技术优化循环结构。 ...
另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。 为了解决上述问题,提出一种使用友元的方案。友元是一种定义在类...
这么做可以消除函数调用和返回所带来的开销(寄存器存储和恢复),而且,由于编译器会把调用函数的代码和函数本身放在一起优化,所以也有进一步优化代码的可能。如果你把一
inline函数(内联函数)从概念上讲是编译器使用函数实现的真实代码来替换每一次的函数调用,带来的最直接的好处就是节省了函数调用的开销,而缺点就是增加了所生成字节码的尺寸。基于此,在代码量不是很
从系统内部来讲,当一个Windows函数检测到一个错误时,它会使用一个称为线程本地存储器的机制,将相应的错误代码号码与调用的线程关联起来。(“线程本地存储器”将在第21章中介绍)。这将使线程能够互相独立地运行...
该例子与上面的例子输出相同的结果,只是调用时的参数不一样。 this指针 this指针是一个隐含于每一个成员函数中的特殊指针。它是一个指向正在被该成员函数操作的对象,也就是要操作该成员函数的对象。 当对一个...
当然,引入内联函数的主要目的是:解决程序中函数调用的效率问题。 另外,前面我们讲到了宏,里面有这么一个例子: #define ABS(x) ((x)>0? (x):-(x)) 当++i出现时,宏就会歪曲我们的意思,换句话说就是:宏的定义...
2.为了降低函数调用的时间开销,建议将小的调用频繁的函数定义为(内联函数 ),方法是在函数类型前加上(inline)关键字。 3.面向对象的程序设计有四大特征,它们是抽象、封装、( 继承 )、( 多态 )。 4.拷贝构造...
它的设计考虑了性能和简单性,它具有与手工制作的 C++ 原生模块相当的函数调用开销。 请参阅基准。 为什么? Node.js 有一个流行的动态绑定库: node-ffi 。 那么为什么我们需要另一个可以问? 为了性能! 与手工...