内联函数、宏定义和普通函数

内联函数和普通函数的反汇编对比

首先我们再viso studio中编写如下代码:

int add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int d;
	d = add(1,2);
	printf("d=%d\r\n",d);
}

反汇编后得到如下汇编代码:

int add(int a, int b)
{
//入栈保护现场
00B117A0  push        ebp  
00B117A1  mov         ebp,esp  
00B117A3  sub         esp,0CCh  
00B117A9  push        ebx  
00B117AA  push        esi  
00B117AB  push        edi  
00B117AC  lea         edi,[ebp-0CCh]  
00B117B2  mov         ecx,33h  
00B117B7  mov         eax,0CCCCCCCCh  
00B117BC  rep stos    dword ptr es:[edi]  
00B117BE  mov         ecx,offset _549F54B0_consoleapplication1@cpp (0B1C008h)  
00B117C3  call        @__CheckForDebuggerJustMyCode@4 (0B1120Dh)  
	int c = a + b;
00B117C8  mov         eax,dword ptr [a]  
00B117CB  add         eax,dword ptr [b]  
	int c = a + b;
00B117CE  mov         dword ptr [c],eax  
	return c;
00B117D1  mov         eax,dword ptr [c]  
}
//add调用结束,出栈恢复现场
00B117D4  pop         edi  
00B117D5  pop         esi  
00B117D6  pop         ebx  
00B117D7  add         esp,0CCh  //回复sp指针,释放局部变量占用的内存
00B117DD  cmp         ebp,esp  
00B117DF  call        __RTC_CheckEsp (0B11217h) 
00B117E4  mov         esp,ebp  
00B117E6  pop         ebp  
00B117E7  ret 

int main()
{
00CC1930  push        ebp   //基址指针寄存器
00CC1931  mov         ebp,esp  //保存当前堆栈,将栈顶指针存入ebp,当前栈顶和栈低重合
00CC1933  sub         esp,0CCh  //栈顶指针向下偏移0xccbyte,开辟临时变量的空间(栈空间)
00CC1939  push        ebx  
00CC193A  push        esi  
00CC193B  push        edi  
00CC193C  lea         edi,[ebp-0CCh]  
00CC1942  mov         ecx,33h  
00CC1947  mov         eax,0CCCCCCCCh  
00CC194C  rep stos    dword ptr es:[edi]  
00CC194E  mov         ecx,offset _549F54B0_consoleapplication1@cpp (0CCC008h)  
00CC1953  call        @__CheckForDebuggerJustMyCode@4 (0CC1221h)  
	int d;
	d = add(1,2);
//从这里可以看出来,函数参数的入栈方向是自有向左
00CC1958  push        2  //最右边的形参入栈
00CC195A  push        1  //最左边的形参入栈
00CC195C  call        add (0CC1186h)  
00CC1961  add         esp,8  
00CC1964  mov         dword ptr [d],eax  
	printf("d=%d\r\n",d);
00CC1967  mov         eax,dword ptr [d]  
00CC196A  push        eax  
00CC196B  push        offset string "d=%d\r\n" (0CC7B30h)  
00CC1970  call        _printf (0CC104Bh)  
00CC1975  add         esp,8  
}
//main函数调用结束,恢复现场
00CC1978  xor         eax,eax  
00CC197A  pop         edi  
00CC197B  pop         esi  
00CC197C  pop         ebx  
00CC197D  add         esp,0CCh  
00CC1983  cmp         ebp,esp  
00CC1985  call        __RTC_CheckEsp (0CC122Bh)  
00CC198A  mov         esp,ebp  
00CC198C  pop         ebp  
00CC198D  ret  

内联函数的反汇编如下:

int inline add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
000D4710  push        ebp  
000D4711  mov         ebp,esp  
000D4713  sub         esp,0F8h  
000D4719  push        ebx  
000D471A  push        esi  
000D471B  push        edi  
000D471C  lea         edi,[ebp-0F8h]  
000D4722  mov         ecx,3Eh  
000D4727  mov         eax,0CCCCCCCCh  
000D472C  rep stos    dword ptr es:[edi]  
000D472E  mov         eax,dword ptr [__security_cookie (0DA004h)]  
000D4733  xor         eax,ebp  
000D4735  mov         dword ptr [ebp-4],eax  
000D4738  mov         ecx,offset _549F54B0_consoleapplication1@cpp (0DC008h)  
000D473D  call        @__CheckForDebuggerJustMyCode@4 (0D1212h)  
	char aa[20] = "123";
000D4742  mov         eax,dword ptr [string "123" (0D7B30h)]  
000D4747  mov         dword ptr [aa],eax  
000D474A  xor         eax,eax  
000D474C  mov         dword ptr [ebp-18h],eax  
000D474F  mov         dword ptr [ebp-14h],eax  
000D4752  mov         dword ptr [ebp-10h],eax  
000D4755  mov         dword ptr [ebp-0Ch],eax  
	int d=1;
000D4758  mov         dword ptr [d],1  
	d = add(1,2);
//此处并没有调用add函数,而是直接把add函数展开
000D475F  mov         eax,1  
000D4764  add         eax,2  
000D4767  mov         dword ptr [ebp-34h],eax  
000D476A  mov         ecx,dword ptr [ebp-34h]  
000D476D  mov         dword ptr [d],ecx  
	//printf("d=%d\r\n",d);
}
000D4770  xor         eax,eax  
000D4772  push        edx  
000D4773  mov         ecx,ebp  
000D4775  push        eax  
000D4776  lea         edx,ds:[0D47A4h]  
000D477C  call        @_RTC_CheckStackVars@8 (0D123Fh)  
000D4781  pop         eax  
000D4782  pop         edx  
000D4783  pop         edi  
000D4784  pop         esi  
000D4785  pop         ebx  
000D4786  mov         ecx,dword ptr [ebp-4]  
	//printf("d=%d\r\n",d);
}
000D4789  xor         ecx,ebp  
000D478B  call        @__security_check_cookie@4 (0D11EAh)  
000D4790  add         esp,0F8h  
000D4796  cmp         ebp,esp  
000D4798  call        __RTC_CheckEsp (0D121Ch)  
000D479D  mov         esp,ebp  
000D479F  pop         ebp  
000D47A0  ret  
000D47A1  nop         dword ptr [eax]  
000D47A4  add         dword ptr [eax],eax  
000D47A6  add         byte ptr [eax],al  
000D47A8  lods        byte ptr [esi]  
000D47A9  inc         edi  
000D47AA  or          eax,0FFFFE400h  
000D47AF  call        dword ptr [eax+eax]  
000D47B2  add         byte ptr [eax],al  
000D47B4  mov         eax,61000D47h  
000D47B9  popad  
000D47BA  add         ah,cl  

对比上面两份反汇编代码可以看出,编译器在处理内联函数时会直接将其展开到调用的函数中,比普通函数少了一个入栈和出栈的过程。

内联函数的优缺点

系统在运行时,会将内联函数直接展开,而不会进行入栈和出栈操作。这样做的好处是可以节省函数调用带来的时间和空间上的开销,提高代码的执行效率,坏处是会使代码的体积庞大

内联函数和宏定义的区别和相同点

  1. 内联函数和宏定义都是将函数展开,它们都会占用较大的代码空间;
  2. 宏定义在预处理时展开,内联函数在编译时展开;
  3. 编译器在处理内联函数时会进行参数检查,宏定义不会;

使用内敛函数的注意事项

1、不要在递归中使用内联函数;
2、循环次数太多的函数不应使用内敛函数定义;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值