521-C++入门(函数参数,内联,函数重载,C和C++互相调用)

形参带默认值的函数

1.给默认值的时候,只能从右向左给!!!
2.调用效率的问题
3.函数定义处可以给形参默认值,函数声明处也可以给形参默认值
4.形参给默认值的时候,不管是函数定义处给,还是函数声明处给,每一个形参的默认值只能出现一次!!!哪怕值一样也不可以!!!
函数的声明可以无数次,但是定义只能一次。
在这里插入图片描述
上面这样写是错误的,因为编译器从上到下编译,形参默认值是从右向左给

在这里插入图片描述
上面这样可行。因为编译器从上到下编译代码,默认从右向左的顺序看,b=20,a=10

我们看下面例子:
在这里插入图片描述
如果只传入参数a,则b就是使用默认值20
如果给a和b都添加默认值,那么在调用的时候就可以不用传参数了。
在这里插入图片描述
我们给参数是从左向右给,实际上压栈是从右向左压,所以给默认值的时候必须是从右向左给!!!
下面这种写法是错误的!!!
在这里插入图片描述
我们看总代码:
调用效率的问题:效率增高!少了1句move指令

//sum(, 20);这个写法是错误的

int sum(int a, int b = 20);
int sum(int a = 10, int b);
int main()
{
	int a = 10;
	int b = 20;

	int ret = sum(a, b);
	/*
	mov eax, dword ptr[ebp-8]
	push eax 入栈
	
	mov ecx, dword ptr[ebp-4]
	push ecx
	call sum
	*/
	cout << "ret:" << ret << endl;


	/*
	push 14H
	mov ecx, dword ptr[ebp-4]
	push ecx
	call sum
	*/
	ret = sum(a);


	/*
	push 14H
	push 0Ah
	call sum
	*/
	ret = sum();//和sum(20, 50);是一样的


    ret = sum(a, 40);
    /*	
	push 28H
	mov ecx, dword ptr[ebp-4]
	push ecx
	call sum 这个和ret = sum(a);一样
	*/

	return 0;
}

int sum(int a, int b)
{
	return a + b;
}

立即数是在寄存器直接存放,不需要从内存中取。

inline内联函数

inline内联函数 和 普通函数的区别???

inline内联函数:
在编译过程中,就没有函数的调用开销了,在函数的调用点直接把函数的代码进行展开处理了!!!

inline函数不再生成相应的函数符号!!!因为在函数调用点直接展开了!!!

但是不是所有的inline都会被编译器处理成内联函数 - 比如说递归
因为编译器是不执行代码的指令的,所以就不知道递归调用自己多少次。
而且如果这个函数代码量巨大,即使你写内联,编译器也不会内联处理,而且名字可能冲突了。

所以inline只是建议编译器把这个函数处理成内联函数!!!

在debug版本上,inline是不起作用的,因为需要调试;
inline只有在release版本下才能出现

在Linux下执行 g++ -c main.cpp -O2
objdump -t main.o(查看符号判断是否内联了,因为内联函数是没有符号的)

不使用内联函数:

int sum(int x, int y)// *.o文件 函数符号:sum_int_int  在.text段
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;

	int ret = sum(a, b); 
	//此处有标准的函数调用过程 参数压栈,函数栈帧的开辟和回退过程
	//有函数调用的开销   函数的开销远大于x+y的3条指令!!!
	//x+y  mov add mov  循环做1000000次 x+y 函数调用开销大

	return 0;
}

如果使用内联函数:

inline int sum(int x, int y)//inline函数不再生成相应的函数符号
{
	return x + y;
}
int main()
{
	int a = 10;
	int b = 20;

	int ret = sum(a,b);
	//编译器从上到下编译,看到sum函数是inline,直接把a给x,b给y
	//直接处理成 int ret=a+b; 省了函数的调用开销
	return 0;
}

函数重载

什么叫函数重载?
1.一组函数,其中函数名相同,参数列表的个数或者类型不同,那么这一组函数就称作-函数重载。
2.一组函数要称得上重载,一定先是处在同一个作用域当中的。
3.const或者volatile的时候,是怎么影响形参类型的。
4.一组函数,函数名相同,参数列表也相同,仅仅是返回值不同?不叫重载

1.C++为什么支持函数重载,C语言不支持函数重载?
C++代码在产生函数符号的时候,是由函数名+参数列表类型组成的!
C代码在产生函数符号的时候,是由函数名来决定!

3.C++和C语言代码之间如何互相调用?

我们看下面代码,提供了3组函数,函数名都是相同的,但是它们的参数列表不同。
在这里插入图片描述
完整代码:

bool compare(int a, int b)//compare_int_int
{
	cout << "compare_int_int" << endl;
	return a > b;
}
bool compare(double a, double b)//compare_double_double
{
	cout << "compare_double_double" << endl;
	return a > b;
}
bool compare(const char *a, const char *b)//compare_const char*_const char*
{
	cout << "compare_char*_char*" << endl;
	return strcmp(a, b) > 0;
}
int main()
{
	compare(10, 20);//call compare_int_int
	compare(10.0, 20.0);//double -> int
	compare("aaa", "bbb");//const char* => int

	return 0;
}

在这里插入图片描述
这是一个典型的函数重载的调用。
重载函数名字一样,在编译器编译过程中,根据函数调用的时候传入的实参类型来选择合适的重载版本。
一组函数,其中函数名相同,参数列表的个数或者类型不同,那么这一组函数就称作-函数重载

2.函数重载需要注意些什么?
在这里插入图片描述
在C/C++中,函数里面是不能再定义一个函数的,但是在一个函数里面声明一个函数是可以的。
在这里插入图片描述
编译看看:
在这里插入图片描述
这个是什么原因?为什么第二个compare不会去调用double,double的函数重载?为什么要调用带int,int的函数重载?
而且我们看第二个编译结果,显示的是错误。也就是说,第三个compare调用也不是去调用带char*,char*的函数重载,而是也去调用了int,int的函数重载?
为什么都是一股脑地去调用这个函数呢?
在这里插入图片描述
因为在我们的C/C++,都是分作用域的,比如说,我们在全局作用域定义一个全局变量,在函数的局部作用域里面定义一个局部变量,这2个变量的名字是可以相同的,不会产生冲突。
在这里插入图片描述
当我们在函数的局部作用域去使用这个变量时,是优先调用当前最近的作用域定义的那个变量。
如果在局部作用域里面要调用全局作用域的相同名字的变量,可以这样写:
在这里插入图片描述
我们回到刚才讨论的代码compare上,在全局有3个函数的定义,现在呢,我们在main函数局部进行了一个函数的声明,因为调用的话,有函数声明就足够了,main函数的3个compare函数在调用的时候,编译器就在最近的作用域,也就main函数局部作用域看到一个函数的声明,就是compare,所以大家都去调用这个compare函数了。
2.一组函数要称得上重载,一定先是处在同一个作用域当中的。

3.const或者volatile的时候,是怎么影响形参类型的?
在这里插入图片描述
这2个func函数的作用域相同,函数名也相同,看它们的参数列表,是相同还是不相同呢?
在这里插入图片描述
对于编译器来说,它看这2个func函数是一样的。
我们去查看一下:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
对于编译器来说,它们的类型都是整型int,所以2个func函数的符号也是一模一样的,形参类型都是int

我们加个指针看看效果,好像就运行可以了:
在这里插入图片描述
在这里插入图片描述
如果我们把指针移动到const的前面:
在这里插入图片描述
在这里插入图片描述
又报错了。
const或者volatile的时候,是怎么影响形参类型的?(下一篇博客叙述)

一组函数,函数名相同,参数列表也相同,仅仅是返回值不同?不叫重载
因为返回值和函数重载没有关系!

静态(编译时期)的多态:函数重载(在编译时期,在生成指令的时候就要确定好调用哪个函数重载了,因为函数的调用要进行时实参的入栈,call指令调用函数。)

C和C++的相互调用?

C 调用 C++:无法直接调用了!怎么办?
把C++源码扩在extern “C”

C++ 调用 C代码:无法直接调用了!怎么办?
把C函数的声明扩在extern "C"里面

我们写一个.c文件:
在这里插入图片描述
我们在另一个.cpp文件进行调用这个sum函数:
在这里插入图片描述
编译看看:
在这里插入图片描述
链接错误,因为编译器按照C++的标准生成符号(函数名+参数列表),在链接的时候发现这里有一个未定义的符号,就在其他的.obj或者.o文件都找,但是找不到。
在这里插入图片描述
.c文件里的sum函数是按C规则生成符号的,按函数名生成符号的。

C++ 调用 C代码:无法直接调用了!怎么办?
把C函数的声明扩在extern "C"里面
告诉编译器,这个函数是在C语言规则下生成的,所以你在生成符号的时候,不要按照C++的方式,要按照C语言的规则去生成符号。
在这里插入图片描述
在这里插入图片描述

C 调用 C++:无法直接调用了!怎么办?
把C++源码扩在extern "C"

在C++文件实现sum代码:
在这里插入图片描述
在C文件中调用C++文件的sum函数:
在这里插入图片描述
编译看看:
在这里插入图片描述
因为在C文件中,编译器是按照C语言的规则去生成符号的,自然匹配不到C++文件中的函数符号。
怎么解决?

在C++文件中的sum函数实现外部扩上extern C
在这里插入图片描述
在C++文件中告诉编译器,按照C语言的方式生成这个函数的符号
这样在C文件调用这个函数,就可以找到了。
在这里插入图片描述
注意:extern “”是只有C++编译器才认识的
C编译器不认识extern""

我们再来看看下面这种写法:

//__FILE__//这个是直接打印当前代码的文件名称 
//__LINE__//这个是直接打印当前代码的行数 
//上面2个是属于编译器内置的宏 

//只要是C++编译器,都内置了__cplusplus这个宏名
#ifdef __cplusplus//这个宏 
extern "C" {
#endif
	int sum(int a, int b) // sum  .text
	{
		return a + b;
	}
#ifdef __cplusplus
}
#endif
//这样的书写是,如果有定义 __cplusplus这个宏(C++编译器内置的宏),就执行下面的extern C,按照C规则生成函数符号
//如果是用C编译器编译这段代码的话,就没有定义 __cplusplus这个宏,所以就不进去下面的extern C, sum函数也是生成C规则的符号 

这样书写的结果就是:不管是C编译器生成还是C++编译器生成,都是按照C规则去生成函数符号的!都是可以直接给其他的C项目调用的!

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值