前言
对于此类函数,一般的问法是,它与普通函数调用有什么区别?或者说优点?
基本用法
首先在写带默认值函数的时候,形参的默认值必须从右往左写。这点条件来自于函数调用堆栈,形参在入栈的时候是从右往左入栈的。以下为错误用法:
int sum(int a=10,int b)
{
return a+b;
}
这里会报b没有默认值的错误
从汇编角度剖析函数调用堆栈时的三种情况:
1、函数形参不带默认值
int sum(int a,int b)
{
return a+b;
}
int main()
{
int a=10;
int b=20;
int ret1=sum(a,b);
/*
mov eax,dword ptr[ebp-8]
push eax
mov ecx,dword ptr[ebp-4]
push ecx
call sum
*/
return 0;
}
其中在int ret1=sum(a,b)
调用形参a,b的时候,先调用b,再调用a。具体在汇编上,就是先将b的值拿给寄存器,再将寄存器的值入栈,即:
mov eax,dword ptr[ebp-8],push eax
其中ebp-8就是b在main函数堆栈中的地址,ebp-4则是a的地址。
2、函数形参带一个默认值
int sum(int a,int b=20)
{
return a+b;
}
int main()
{
int a=10;
int b=20;
int ret2=sum(a);
/*
push 14H
mov ecx,dword ptr[ebp-4]
push ecx
call sum
*/
return 0;
}
这里容易理解,int ret2=sum(a)
,形参中的b已有默认值,可以直接将b的值入栈。相比1中的情况,这里少了一个将b的值拿入寄存器的指令。
3、函数参数带两个默认值
int sum(int a=10,int b=20)
{
return a+b;
}
int main()
{
int a=10;
int b=20;
int ret3=sum();
/*
push 14H
push 0AH
call sum
*/
return 0;
}
这种情况在分析函数堆栈时,指令就更少了。两个数据都是直接入栈。
总结
对于带默认值的函数与不带默认值函数的对比:带默认值函数在执行时,如果其形参不需要额外变量赋予,而当做常量处理。可以节省指令的执行。如果这种函数执行一万次,其可以节省一些开销。
对于上述地sum函数,执行一万次,经多次测试取平均值,结果如下:
函数情况 | 平均时间开销 |
---|---|
带l两个默认值函数 | 23ms |
不带默认值函数 | 28ms |
可以节省5ms的时间(能省也不错,5ms,蚊子腿也是肉)。