当前位置:  编程技术>c/c++/嵌入式

函数式宏定义与普通函数的区别

    来源: 互联网  发布时间:2014-10-21

    本文导语:  在C及C++语言中允许用一个标识符来表示一个字符串,称为宏,该字符串可以是常数、表达式、格式串等。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏...

在C及C++语言中允许用一个标识符来表示一个字符串,称为宏,该字符串可以是常数、表达式、格式串等。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。若字符串是表达式,我们称之为函数式宏定义,那函数式宏定义与普通函数有什么区别呢?

我们以下面两行代码为例,展开描述:
函数式宏定义:#define MAX(a,b) ((a)>(b)?(a):(b))
普通函数 :MAX(a,b) { return a>b?a:b;}

(1)函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。

(2)调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。

如果MAX是个普通函数,那么它的函数体return a > b ? a : b; 要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果MAX是个函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。

(3)函数式宏定义要注意格式,尤其是括号。

如果上面的函数式宏定义写成 #define MAX(a, b) (a>b?a:b),省去内层括号,则宏展开就成了k = (i&0x0f>j&0x0f?i&0x0f:j&0x0f),运算的优先级就错了。同样道理,这个宏定义的外层括号也是不能省的。若函数中是宏替换为 ++MAX(a,b),则宏展开就成了 ++(a)>(b)?(a):(b),运算优先级也是错了。

(4)若函数参数为表达式,则普通函数的调用与函数式宏定义的替换过程是不一样的。

普通函数调用时先求实参表达式的值再传给形参,如果实参表达式有Side Effect,那么这些SideEffect只发生一次。例如MAX(++a, ++b),如果MAX是普通函数,a和b只增加一次。但如果MAX函数式宏定义,则要展开成k = ((++a)>(++b)?(++a):(++b)),a和b就不一定是增加一次还是两次了。所以若参数是表达式,替换函数式宏定义时一定要仔细看好。

(5)函数式宏定义往往会导致较低的代码执行效率。

看下面一段代码:

代码如下:

int a[]={9,3,5,2,1,0,8,7,6,4};
int max(n)
{
    return n==0?a[0]:MAX(a[n],max(n-1));
}

int main()
{
    max(9);
    return 0;
}


若是普通函数,则通过递归,可取的最大值,时间复杂度为O(n)。但若是函数式宏定义,则宏展开为( a[n]>max(n-1)?a[n]:max(n-1) ),其中max(n-1)被调用了两遍,这样依此递归下去,时间复杂度会很高。

尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。


    
 
 

您可能感兴趣的文章:

  • linux c malloc函数定义及用法详解
  • 请问:定义了2个函数,其中第一个函数要访问另外一个函数的变量,怎么处理阿?谢谢
  • 数据库 iis7站长之家
  • 如何定义一个可变参数的自定义函数
  • 函数有定义怎么提示没有低能定义的错误呢?
  • Python过滤函数filter()使用自定义函数过滤序列实例
  • 请问如何在一个函数内部定义的一个新类中使用函数里声明的变量
  • 急:unix的shell脚本中,定义了一个函数getDate(),在后面的执行命令参数用要使用这个函数的返回值,应该怎么写?
  • 有谁说说jsp中的变量与函数定义
  • 问个在模块中调用内核函数的未定义问题
  • linux shell自定义函数(定义、返回值、变量作用域)介绍
  • signal函数定义该怎么理解?
  • 谁能告诉我这些函数的定义在哪里?
  • Linux C 有没有 查看函数定义的方法?
  • android自定义控件和自定义回调函数步骤示例
  • 怎么查找一个函数在哪个文件中定义的
  • linux下Eclipse+CDT,如何查看函数的定义、声明
  • 在sql Server自定义一个用户定义星期函数
  • java中函数的缺省参数怎么定义?
  • 自定义的函数可以返回“类”吗?
  • signal函数的定义问题?搞不懂.
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • C++ Maps 成员 key_comp():返回比较元素key的函数
  • 如果知道一个函数的地址或函数名,如何得到函数所在的文件名?
  • C++ Maps 成员 value_comp():返回比较元素value的函数
  • java的数学函数在那个类中,如幂函数、指数、对数、双曲线函数等?
  • C++ MultiMaps 成员 key_comp():返回比较key的函数
  • 一个父类的构造函数的参数是(Applet applet),请问它的子类构造函数当中应怎样调用父类构造函数?
  • C++ MultiMaps 成员 value_comp():返回比较元素value的函数
  • 虚函数被类的构造析构函数和成员函数调用虚函数的执行过程
  • C++ STL Bitsets构造函数及成员函数解释及代码示例
  • 在内核的某个函数中,如何能知道是哪个用户空间的函数调用了它,以及这个用户空间函数所在的文件?
  • C++ Strings(字符串) 成员 Constructors:构造函数,用于字符串初始化
  • 在dos下访问内存的MK_FP函数在linux下对应什么函数?int86()函数呢?
  • linux c 生成随机数srand函数和rand函数介绍及代码示例
  • 一个静态库包含多个函数,应用程序连接了库中的某个函数,应用程序目标代码中是否还包含了该静态库中的其他函数代码?
  • Linux下gettimeofday()函数和clock()函数:精确到毫秒级的时间
  • Oracle 函数大全[字符串函数,数学函数,日期函数]第1/4页
  • Linux c++虚函数(virtual function)简单用法示例代码
  • js的众多函数令小弟实在搞不清楚!哪有函数速查手册之类的软件或者书籍!谢了!比如,setInterval、clearInterval这两个函数是干什么的?
  • sharepoint 2010 使用STSNavigate函数实现文件下载举例
  • 虚函数与纯虚函数(C++与Java虚函数的区别)的深入分析
  • cityhash 32位,64位和128位介绍及函数列表
  • 谁能告诉我,在JAVA中,哪个函数和ASP中的Int()函数等同,也就是取整函数


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3