我是靠谱客的博主 整齐蛋挞,最近开发中收集的这篇文章主要介绍【C/C++内功心法】详解宏和函数的区别前言一、宏和函数的对比二、宏和函数的命名约定总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

前言

一、宏和函数的对比

1.宏的优点

2.宏的缺点

3.宏的独特性

4.总结并整理宏和函数的区别

5.有没有宏和函数的结合体?

二、宏和函数的命名约定

总结


前言

大家好啊,我是不一样的烟火a,今天我将会为大家讲解面试中常被问到的问题——宏和函数的区别。本篇文章对基础薄弱的小伙伴十分友好,相信只要看完一定能收获满满。


一、宏和函数的对比

1.宏的优点

  • 宏通常被应用于执行简单的运算。
  • 比如在两个数中找出较大的一个。
#define MAX(a, b) ((a)>(b)?(a):(b))

那为什么不用函数来完成这个任务?

原因有两点:

  • 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。

所以宏比函数在程序的规模和速度方面更胜一筹。

举例:

  • 用宏实现两个数中找出较大值。
#define MAX(x, y) ((x) > (y) ? (x) : (y))
int main()
{
int a = 10;
int b = 20;
int c = MAX(a, b); // 宏
return 0;
}

转到反汇编,查看汇编代码。

	int c = MAX(a, b); // 宏
00791783
mov
eax,dword ptr [a]
00791786
cmp
eax,dword ptr [b]
00791789
jle
__$EncStackInitStart+3Ah (0791796h)
0079178B
mov
ecx,dword ptr [a]
0079178E
mov
dword ptr [ebp-0E8h],ecx
00791794
jmp
__$EncStackInitStart+43h (079179Fh)
00791796
mov
edx,dword ptr [b]
00791799
mov
dword ptr [ebp-0E8h],edx
0079179F
mov
eax,dword ptr [ebp-0E8h]
007917A5
mov
dword ptr [c],eax

  • 用函数实现两个数中找出较大值。
int Max(int x, int y)
{
return ((x) > (y) ? (x) : (y));
}
int main()
{
int a = 10;
int b = 20;
int c = Max(a, b); // 函数
return 0;
}

调用函数的汇编代码。

	int c = Max(a, b); // 函数
002C1793
mov
eax,dword ptr [b]
002C1796
push
eax
002C1797
mov
ecx,dword ptr [a]
002C179A
push
ecx
002C179B
call
_Max (02C139Dh)
// 调用Max函数
002C17A0
add
esp,8
002C17A3
mov
dword ptr [c],eax

计算的汇编代码。

int Max(int x, int y)
{
002C1DF0
push
ebp
002C1DF1
mov
ebp,esp
002C1DF3
sub
esp,0C4h
002C1DF9
push
ebx
002C1DFA
push
esi
002C1DFB
push
edi
002C1DFC
lea
edi,[ebp-4]
002C1DFF
mov
ecx,1
002C1E04
mov
eax,0CCCCCCCCh
002C1E09
rep stos
dword ptr es:[edi]
002C1E0B
mov
ecx,offset _66EADA86_详解预处理test@c (02CC000h)
002C1E10
call
@__CheckForDebuggerJustMyCode@4 (02C1307h)
// 下面这些才是计算的代码,上面这些代码可以说还是在为调用函数做准备
// 并且可以看出下面的汇编代码和宏那里的汇编代码是一样的
return ((x) > (y) ? (x) : (y));
002C1E15
mov
eax,dword ptr [x]
002C1E18
cmp
eax,dword ptr [y]
002C1E1B
jle
__$EncStackInitStart+2Ch (02C1E28h)
002C1E1D
mov
ecx,dword ptr [x]
002C1E20
mov
dword ptr [ebp-0C4h],ecx
002C1E26
jmp
__$EncStackInitStart+35h (02C1E31h)
002C1E28
mov
edx,dword ptr [y]
002C1E2B
mov
dword ptr [ebp-0C4h],edx
002C1E31
mov
eax,dword ptr [ebp-0C4h]
}

函数返回的汇编代码。

002C1E37
pop
edi
002C1E38
pop
esi
002C1E39
pop
ebx
002C1E3A
add
esp,0C4h
002C1E40
cmp
ebp,esp
002C1E42
call
__RTC_CheckEsp (02C1230h)
002C1E47
mov
esp,ebp
002C1E49
pop
ebp
002C1E4A
ret

总结:

如果用函数的话,会经过以下几个步骤:

  • 函数调用。
  • 计算。
  • 函数返回。

根据上面的汇编代码可以看出,函数调用和函数返回所用的汇编指令远多于计算所用的汇编指令,这就导致函数调用和返回所用的时间远多于计算所用的时间。而宏本质是替换,不用进行函数调用和返回,所以这就是宏在实现小型计算工作时比函数快的原因。

  • 更为重要的是函数的参数必须声明为特定的类型。

所以函数只能在类型合适的表达式上使用。

而宏是类型无关的,宏可以适用于整形、长整型、浮点型等,可以用于 “>” 来比较的类型。

举例:

下面为宏和函数实现的两个数中找出较大值。

// 宏
#define MAX(x, y) ((x) > (y) ? (x) : (y))
// 函数
int Max(int x, int y)
{
return ((x) > (y) ? (x) : (y));
}

可以看出,该函数只能对两个int类型的数进行比较,而宏却可以对两个任意类型的数进行比较,这就使宏用起来更加的灵活。


2.宏的缺点

  1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
  2. 宏是没法调试的。
  3. 宏由于类型无关,也就不够严谨。
  4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

3.宏的独特性

宏有时候可以做函数做不到的事情。

比如:宏的参数可以出现类型,但是函数做不到。

#define MALLOC(num, type) (type*)malloc(num * sizeof(type))
int main()
{
// 使用
int* p1 = MALLOC(10, int); // 替换后为 int* p1 = (int*)malloc(10 * sizeof(int));
char* p2 = MALLOC(5, int); // 替换后为 int* p2 = (char*)malloc(5 * sizeof(char));
return 0;
}

4.总结并整理宏和函数的区别

#define定义宏函数

每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码

更快存在函数的调用和返回的额外开销,所以相对慢一些

宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号。函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预 测。

参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。函数参数只在传参的时候求值一 次,结果更容易控制。

宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型。函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是 不同的。

宏是不方便调试的函数是可以逐语句调试的

宏是不能递归的函数是可以递归的

5.有没有宏和函数的结合体?

答案是当然有。

在C99和C++里面都有一个东西叫做内联函数(inline)

内联函数既有函数的优点又有宏的优点:

  • 宏的优点:内联函数没有函数的调用和返回。
  • 函数的优点: 内联函数本身是个函数,它没有参数优先级、副作用等宏的缺点。

提示:由于本篇文章主要是讲宏和函数的区别,内联函数就不多讲,这里只做了解,后面我会单独写一篇文章来讲解内联函数的。


二、宏和函数的命名约定

一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。

那么我们平时就应该有一个良好的书写习惯:

  • 把宏名全部大写
  • 函数名不要全部大写
  • 这里可以参考《高质量C/C++编程指南》这本书,有兴趣的小伙伴可以去看看。

总结

以上就是宏和函数区别的所有内容了,并且都是高频考点,所以大家一定要牢记于心。如果大家有什么解决不了的问题,欢迎大家评论区留言或者私信告诉我。如果感觉对自己有用的话,可以点个赞或关注鼓励一下博主,我会越做越好的,感谢各位的支持。

最后

以上就是整齐蛋挞为你收集整理的【C/C++内功心法】详解宏和函数的区别前言一、宏和函数的对比二、宏和函数的命名约定总结的全部内容,希望文章能够帮你解决【C/C++内功心法】详解宏和函数的区别前言一、宏和函数的对比二、宏和函数的命名约定总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部