C89标准中,c语言没有带有默认值的参数,c99之后才有
给函数默认值既可以在定义处,也可以在声明处,但只能给一次默认值
第一次声明时给最右边的参数一个默认值,第二次声明时给左边参数一个默认值也是合法的(vs2008中合法,但是vs2017中是非法的)
赋默认值必须从右向左依次赋值,在调用时,如果没有给实参,则把参数默认值压栈,也可以只传没有默认值的那个参数。
使用有默认值的函数可以提高效率(少一步汇编过程,节省一个mov指令的周期)
使用函数的默认值时相当于直接传递一个即时数
我们在一个文件中定义了sum函数,想要在另一个文件中使用它,因此在另一个文件中对其进行了声明,这在编译链接时是没有问题的
但是如果在该函数的定义处加上inline关键字,你会发现系统报了一个“无法解析的外部符号”的错误。这是为什么呢?
内联函数不产生符号,在函数的调用点,把函数的代码全部展开(编译时完成)
这个过程和宏的使用很相似,但是宏替换是在预编译阶段就进行的,不进行任何的检查,只进行字符串的替换。因此可以把内联函数成为更安全的宏(类型检查,编译阶段)
内联函数 和 普通函数的区别
1·内联函数没有标准的函数栈帧的开辟和回退
2·内联函数仅在当前文件可见,不产生符号(一般定义在头文件中)
内联函数 和 static函数的区别
1·static函数有正常的栈帧开辟和回退的过程
2·static函数产生一个local的符号,内联函数不产生符号
3·都是仅在当前文件可见
注意:内联函数只在release版本起作用,在debug版本里面,也需要开辟和回退栈帧(方便调试)
C语言中函数的符号由函数名称产生,c++中函数的符号由函数名称和形参的类型和形参的个数共同产生
1·函数名相同,参数列表不同的函数称作一组重载函数,不能仅通过返回值不同来重载函数,因为产生符号和返回值无关
2·静多态 :函数重载 模板 动多态 :继承里面的多态(虚函数)
3·重载函数必须处于同一作用域下
C语言中允许在一个函数中声明另外一个函数
如图我们在主函数中对compare函数重新声明,这里我们只声明了int型参数的一个重载,可以看到第三个调用报错,这是为什么呢?
在c和c++中可以定义全局和局部的同名函数,但是在局部调用时,默认优先调用局部声明的函数 ,局部没有声明的情况下再去搜索全局的,这个例子中主函数里已经有了cmopare函数的声明,因此不会再去全局作用域中搜索,但主函数里声明的compare函数的参数是int型的,double型进行默认转换也可以调用int型参数的compare函数,但是在字符串比较时就会出错。
如果重载的时候把double类型参数的重载定义成float会出错,这是因为我们的浮点数默认类型为double型,主函数在执行compare(10.5,20.6)这句代码时,不知道要调用哪个重载函数,这是需要把实参的类型定义成准确类型(重载中存在的类型),在这里是compare(10.5f,20.6f)。
默认类型转换顺序(横向是无条件转换,纵向是当出现纵向两种类型比较时的转换顺序)
由于c和c++产生的符号不同,要想直接调用会出错
C++调用c代码时可以加上extern “C”关键字,说明里面的符号是按照c语言的规则生成,如下
C语言调用c++如何实现?
把c++代码用大括号括起来,在前面加上extern “C”,这样的话,这段c++代码就会产生c语言的符号,就能被调用了
C++调用c的时候不用看到c的源代码,直接在c++声明处使用extern“C“,但是c调用无法看到源代码的c++比较麻烦,这时我们可以自己写一个c++文件,把要调用的函数封装起来
c语言中const是常变量,加上和不加唯一的区别就是长变量不能作为左值存在,但归根究底还是一个变量,c语言中const修饰的变量可以不被初始化,若不初始化则不能再给其赋值,不能用const修饰的变量作为数组的下标 (C89标准,C99以后同C++),
c++中const修饰的量是常量,必须初始化,可以作为数组的下标,编译时,所有使用常量名的地方全部替换成常量的值。当c++中的常量引用一个编译阶段不明确的值的时候,就会退化成常变量,此时不能再作为数组的下标。
如要在c++其他文件使用该文件中的常量,可以在定义处加上extern关键字,常量生成符号默认为local的,加上extern时则会产生一个global的符号。
我们通过汇编代码可以发现,引用的本质其实就是一个常指针,指向不能改变。编译器对引用的处理和对指针的处理是相同的,引用相当于对一个指针解引用,引用变量的地址无法访问,都会转换成对指针的解引用操作,变成对所指向的变量的操作
1·引用变量必须初始化
2·初始化的值必须要能取地址(不能是一个即时数)
3·引用不能改变
4·访问引用变量,永远访问的是它所引用的内存
我们先来看一下这四句代码里面哪个p都是常量?其实只有后面两个是常量,怎么区分呢?
首先要注意const和一级指针结合的时候会有两个方面,一个是她所修饰的类型,一个是她所修饰的表达式,const修饰的类型怎么判断呢,大家记住:const向左或向右遇到的第一个完整的类型就是const所修饰的类型,而表达式就是const右边的变量,在这里前两个const修饰的表达式是*p,第三那个修饰的是p本身,第四个有两个const,分别修饰*p和p。
Const修饰谁,谁就是常量,在这里前两个表达式中*p是常量,也就是说,指针p所指向的值不允许被修改(p的解引用),第三个是p本身是一个常量,即p所保存的地址不允许被修改(p的值),第四个p的值和p的指向的值都不允许被修改。
定义一个常量a,然后用一个整型指针指向他,这里为什么会出错?
判断一个const类型会不会出错,主要看const所修饰的常量的指针或者引用会不会被泄露出去,我们上面的操作相当于把一个常量的地址泄露给一个指针变量,常量不允许被修改,但是我们可以通过修改指针的解引用来修改常量的值,这当然是不被允许的。
修改成这样就可以了。
const和引用结合只有一种方式,即cosnt int &b(不能写成int & const b)。对于常量来说只能用一个常引用来引用该常量
上面代码中,第一行,用a去引用一个常量,这明显是错误的,因为常量无法取地址,而一个引用里面保存的就是其所引用的变量的地址,自然会出错。但是定义一个常引用去引用一个即时数却是可以通过编译的,这是为什么呢?
C++编译器在处理常引用引用一个即时数这种情况的时候,会生成一个临时量temp,它的值是这个即时数的值,而引用里面保存的就是这个临时量的地址
这段代码中的三个二级指针q有什么不同?
第一个const修饰的表达式是**q,意思是**q这个二级指针解引用的值是一个常量,无法修改,但是q的指向和*q的指向都是可以改变的。
第二个const修饰的表达式是二级指针q本身,说明该二级指针本身就是一个常量,它里面保存的地址无法改变,即这个二级指针指向的一级指针不能改变。
第三个const修饰的是*q,说明*q是一个常量,不能被赋值,但是*q这个一级指针的指向可以改变