c语言宏定义问题 宏定义不是可以实现和函数相同功能 那为什么还要分函数和宏定义两种功能?
2个回答
展开全部
现在的教科书啊, c语言的标准定义,是不包括宏的。
宏是编译器的一部分,我们通常写代码,为了代码高可用等,一般离不开使用宏。
宏定义是编译器的预处理器处理的,真正编译的时候,才是解析具体的语言语法,
具体宏定义的使用,还得看编译器的支持了。
宏只有一个特征:就是字符串替换。预处理器处理宏的时候,就是把代码中的宏,替换为宏代表的字符串,至于加的一些#if #else的逻辑,也是可以理解为替换。
宏定义不能实现和函数的相同功能,函数可以划分域,会占用栈,可以做接口,高复用代码。
而宏就不一样了,纯粹替换字符串, 不能划分域,那你只用宏,就会整个文件都在同一个作用域,定义一个变量,其它宏还不能随便重名... ...
再比如,我写一个函数,编译之后,只占4k空间,然后,这个函数被10000处调用,但是仍然只需要4k空间来存储函数代码,如果你换成宏,每一处调用都会占用4k空间的(因为是字符串替换),所以,会引起实际占用4K * 10000 = ? ,拿操作系统不用运行了
就按照上边的区别去想,自然解答了你这个问题。
宏是编译器的一部分,我们通常写代码,为了代码高可用等,一般离不开使用宏。
宏定义是编译器的预处理器处理的,真正编译的时候,才是解析具体的语言语法,
具体宏定义的使用,还得看编译器的支持了。
宏只有一个特征:就是字符串替换。预处理器处理宏的时候,就是把代码中的宏,替换为宏代表的字符串,至于加的一些#if #else的逻辑,也是可以理解为替换。
宏定义不能实现和函数的相同功能,函数可以划分域,会占用栈,可以做接口,高复用代码。
而宏就不一样了,纯粹替换字符串, 不能划分域,那你只用宏,就会整个文件都在同一个作用域,定义一个变量,其它宏还不能随便重名... ...
再比如,我写一个函数,编译之后,只占4k空间,然后,这个函数被10000处调用,但是仍然只需要4k空间来存储函数代码,如果你换成宏,每一处调用都会占用4k空间的(因为是字符串替换),所以,会引起实际占用4K * 10000 = ? ,拿操作系统不用运行了
就按照上边的区别去想,自然解答了你这个问题。
TableDI
2024-07-18 广告
2024-07-18 广告
VLOOKUP函数是Excel中用于数据匹配的重要工具。其使用方法是:在个参数中输入要查找的值,第二个参数是包含数据的范围或表格,第三个参数指定返回数据的列号,第四个参数(可选)决定查找方式(0为精确匹配,其他为近似匹配)。例如,假设我们想...
点击进入详情页
本回答由TableDI提供
展开全部
我们以下面两行代码为例,展开描述:
函数式宏定义:#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)被调用了两遍,这样依此递归下去,时间复杂度会很高。
尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。
函数式宏定义:#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)被调用了两遍,这样依此递归下去,时间复杂度会很高。
尽管函数式宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数式宏定义来代替实现。
本回答被提问者采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询