一、函数的默认值
int sum(int a,int b)
{
return a+b;
}
int main()
{
int a = 10;
int b = 20;
sum(a,b);
}
以上代码sum(a,b)的反汇编为
00C3144C mov eax,dword ptr [b]
00C3144F push eax
00C31450 mov ecx,dword ptr [a]
00C31453 push ecx
00C31454 call sum (0C3105Fh)
00C31459 add esp,8
如果将sum函数设置默认值,即
int sum(int a,int b = 20)
{
return a+b;
}
int main()
{
int a = 10;
sum(a);
//sum(a,30);30为立即数
}
以上代码sum函数的反汇编为
00231445 push 14h
00231447 mov eax,dword ptr [a]
0023144A push eax
0023144B call sum (023105Fh)
00231450 add esp,8
与未初始化的函数相比就少了一步mov b的过程。
默认值的总结:
默认值是从右往左赋值的,绝不可以int sum(int a = 10,int b);
但是在函数声明的时候可以这样写:
int sum(int a,int b=20);
int sum(int a=10,int b);
这是因为在前一行的sum函数中已经给b赋值了
但是如果将以上两句函数声明倒过来写,将原来的第一句放在第二句的位置,就不行了,因为编译器是从上往下编译的,原来的第二句并没有给b先赋值。
二、inline内联函数
1、在调用点把代码直接展开(不会给sum函数开辟栈,而是直接的替换。)
例:
inline int sum(int a,int b)
{
return a+b;
}
int main()
{
int ret = sum(10,20);//将此句直接转换为:ret = 10+20
}
2、宏(#define)和内联函数(inline)的区别
宏:处于预编译阶段,不会做的词法解析以及类型检查,出错的可能性高,不安全。
下面举一个例子:
#define Max(a,b) a>b?a:b
int main()
{
int a = Max(10,20)+20;
printf("%d\n",a);
return 0;
}
上面这段代码输出的会是什么呢?
输出的是:40
为什么呢?
上面说过了,宏定义就是字符替换,所以原函数中的a = Max(10,20)+20就变为了a = 10>20?10:(20+20)。
内联函数:处于编译阶段,有进行词法解析以及类型检查,只要有错误就会编译失败,所以说inline函数是安全的。
3、内联函数和普通函数的区别
普通函数:需要开辟栈帧,清理栈帧(栈的回退)。
内联函数:没有栈帧的开辟及回退。
4、内联函数和static函数的区别
static函数:生成符号、符号属性;需要开辟栈帧,清理栈帧(栈的回退)。
内联函数:不产生符号;没有栈帧的开辟及回退。
static和inline函数的相同点:都只能在当前文件中使用。
另:普通函数与static函数的区别:普通函数中的变量是global全局变量,static函数中的是local局部变量。
Q:我们在什么时候用内联函数呢?
A:在栈帧开辟的开销(函数调用的开销)>函数执行的开销时。
最后需要注意的是:1、inline函数只在release版本中生效,在debug版本中的inline函数的调用也需要栈帧的开辟和回退。
2、inline函数只是对编译器的一个建议,最终能不能起作用是由编译器来决定的。比如:inline函数对递归函数不起作用,因为不知道需要展开函数几次。
三、函数的重载
c语言:函数产生符号由函数名称决定,所以函数的定义不能重名,否则出现重定义。
C++:函数产生符号由函数名称+形参的类型+形参的个数决定。函数定义可以重名,但前提是函数的参数不能完全相同。
例如:
bool compare(int a,int b)
{
cout<<"compare(int,int)"<<endl;
return a>b;
}
bool compare(double a,double b)
{
cout<<"compare(double,double)"<<endl;
return a>b;
}
bool compare(char* a,char* b)
{
cout<<"compare(char*,char*)"<<endl;
return strcmp(a,b)>0?true:false;
}
int main()
{
compare(10,20);
compare(10.5,20.6);
compare("hello","world");
return 0;
}
上方的函数在C语言中不能编译成功,因为函数重定义了。
而在C++中,三个函数名称分别为:compare_int_int;compare_double_double;compare_char*_char*
所以,1、我们把函数名相同,参数列表不同的函数称为一组重载函数。2、重载必须处于同一个作用域中。例:如果在主函数中加入一行函数声明
int main()
{
compare(int a,int b);
compare(10,20);
compare(10.5,20.6);
compare("hello","world");
return 0;
}
再编译时就会出现类型无法转换的情况。
如果将以上代码改为
bool compare(int a,int b)
{
cout<<"compare(int,int)"<<endl;
return a>b;
}
bool compare(float a,float b)
{
cout<<"compare(float,float)"<<endl;
return a>b;
}
bool compare(char* a,char* b)
{
cout<<"compare(char*,char*)"<<endl;
return strcmp(a,b)>0?true:false;
}
int main()
{
compare(10,20);
compare(10.5,20.6);
compare("hello","world");
return 0;
}
编译时就会出错,不知将10.5和20.6转换为int还是double类型。
箭头所指的线路都是编译器默认会选择的优先转向。
比如short类型参与运算时,都会默认转换成int型计算,最后再将结果转化为short,这样做是为了提高精度。
为了更好的理解,下面举出一个例子:
unsigned int a = 1;
char b = -1;
char c = a>b?'a':'b';//b
cout<<c<<endl;
unsigned short a = 1;
char b = -1;
char c = a>b?'a':'b';//a
cout<<c<<endl;
四、C与C++的相互调用
1、C++转C(看得见源代码)
2.1、C转C++
2.2、C转C++(看不见源代码)