十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
区别:
创新互联的客户来自各行各业,为了共同目标,我们在工作上密切配合,从创业型小企业到企事业单位,感谢他们对我们的要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。专业领域包括成都做网站、成都网站建设、成都外贸网站建设、电商网站开发、微信营销、系统平台开发。
1、宏会在编译器在对源代码进行编译的时候进行简单替换,不会进行任何逻辑检测,即简单代码复制而已。
2、宏进行定义时不会考虑参数的类型。
3、参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,即会增长目标文件的大小。
4、参数宏的运行速度会比函数快,因为不需要参数压栈/出栈操作。
5、参数宏在定义时要多加小心,多加括号。
6、函数只在目标文件中存在一处,比较节省程序空间。
7、函数的调用会牵扯到参数的传递,压栈/出栈操作,速度相对较慢。
8、函数的参数存在传值和传地址(指针)的问题,参数宏不存在。
宏只是字符的替换,在预处理阶段就给替换到代码中去了比如下面的代码
#include
#define
MAX(x,
y)
((x)(y)?(x):y())
int
main()
{
int
a
=
2,
b
=
4;
int
m;
m
=
MAX(2,
4);
printf("%d\n",
m);
return
0;
}
如果你用的是gcc编译器,执行
gcc
-E
main.c
-o
main.i,打开main.i文件就可以看到他是如何替换进去的,直接拖到最后,前面的都是stdio.h中的内容。
int
main()
{
int
a
=
2,
b
=
4;
int
m;
m
=
((2)(4)?(2):4());
printf("%d\n",
m);
return
0;
}
函数就不同了,函数还需要分配栈空间,在执行函数时都要进行入栈和出栈操作,有的还需要分配堆空间。
宏所实现的功能有限,而且长代码不易读,但是对于逻辑简单、代码不长、经常使用的功能由宏来实现是个不错的选择
不同。
虽然功能近似,但函数会产生独立代码,每次调用执行的是同一个位置的代码,无论调用多少次。
宏定义是简单的文本替换,产生的代码是替换后程序产生的代码,简单说就是程序里每次使用宏替换后的地方都要产生类似的代码,而这些替换后产生的代码存在于程序的不同位置。
宏定义不检查参数类型,仅仅是简单的文本替换
我们以下面两行代码为例,展开描述:
函数式宏定义:#define MAX(a,b) ((a)(b)?(a):(b))
普通函数 :MAX(a,b) { return ab?a:b;}
(1)函数式宏定义的参数没有类型,预处理器只负责做形式上的替换,而不做参数类型检查,所以传参时要格外小心。
(2)调用真正函数的代码和调用函数式宏定义的代码编译生成的指令不同。
如果MAX是个普通函数,那么它的函数体return a b ? a : b; 要编译生成指令,代码中出现的每次调用也要编译生成传参指令和call指令。而如果MAX是个函数式宏定义,这个宏定义本身倒不必编译生成指令,但是代码中出现的每次调用编译生成的指令都相当于一个函数体,而不是简单的几条传参指令和call指令。所以,使用函数式宏定义编译生成的目标文件会比较大。
(3)函数式宏定义要注意格式,尤其是括号。
如果上面的函数式宏定义写成 #define MAX(a, b) (ab?a:b),省去内层括号,则宏展开就成了k = (i0x0fj0x0f?i0x0f:j0x0f),运算的优先级就错了。同样道理,这个宏定义的外层括号也是不能省的。若函数中是宏替换为 ++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)被调用了两遍,这样依此递归下去,时间复杂度会很高。
尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。
代码如下:
#include "stdio.h"
void main()
{
float a, b ,c;
printf ("请输入三个数,会为你从大到小排列!\n");
scanf("%f %f %f",a,b,c);
if(abc){printf("%f,%f,%f",a,b,c);}
else if(accb){printf("%f,%f,%f",a,c,b);}
else if(baac){printf("%f,%f,%f",b,a,c);}
else if(bcca){printf("%f,%f,%f",b,c,a);}
else if(cbba){printf("%f,%f,%f",c,b,a);}
else if(caab){printf("%f,%f,%f",c,a,b);}
//编译器不识别三个连续的符号运算,必须用且()和或(||)he否(!)
}
扩展资料
C语言中宏定义的优点
方便程序的修改
使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时, 可以用较短的有意义的标识符来写程序,这样更方便一些。
相对于==全局变量==两者的区别如下:
1、宏定义在编译期间即会使用并替换,而全局变量要到运行时才可以。
2、宏定义的只是一段字符,在编译的时候被替换到引用的位置。在运行中是没有宏定义的概念的。而变量在运行时要为其分配内存。
3、宏定义不可以被赋值,即其值一旦定义不可修改,而变量在运行过程中可以被修改。
4、宏定义只有在定义所在文件,或引用所在文件的其它文件中使用。 而全局变量可以在工程所有文件中使用,只要再使用前加一个声明就可以了。换句话说,宏定义不需要extern。
宏定义的基础知识。引用宏定义时,直接代入进行代换。
既然已经宏定义SUB(a) (a)-(a),而程序中出现的对应a的是a+b,那么就将a换为a+b代入表达式:
d=SUB(a+b)*c=(a+b)-(a+b)*c=(2+3)-(2+3)*5
直接用(a+b)-(a+b)代换SUB(a+b)。这一点和数学是不同的,不要强行往数学上靠。