1.c和c++函数互相调用
之前也说了,c和c++的函数生成符号不一样,那么c++和c在互相调用对方函数的时候就会出错,因为根本无法找到对应的符号。
而由于c++是基于c语言而来,肯定会想到兼容性的问题,因此如果c++想要使用c的函数,c++会有特殊处理,可以把函数符号转化成c的不带参数的形式,只用在c++文件里这样
Extern ”C”
{
Int sum(int ,int )
}
这样编译时同时也会生成c语言版本的函数符号,到时候c++想要使用c中定义的函数也可以找到符号。
但是反过来呢,如果c想要使用c++文件里定义的函数呢。c可是不会兼容c++的,c可不能在自己文件里使用extern”c++”这种东西。
那么该怎么做呢?
其实可以创建一个接口文件。
比如这是cpp文件
Sum.cpp
Int sum(int a,int b)
{
Return a+b;
}
这是.c文件
Main()
{
Int a=10;
Int b=20;
sum(a,b);
}
目前来看,.c文件是绝对使用不了.cpp里的sum定义的。
那么这时就要新建一个mid.cpp接口文件了
这个文件内容如下
Mid.cpp
Int sum(int a,int b)
extern”C”
{
Mysum(int a,int b)
{
return sum(a,b);
}
}
2.const用法
c语言里const是常变量,而c++里是常量,即立即数。
因此c语言里const修饰的变量并不能作为初始化数组长度的下标。
而c++里const修饰的变量编译时就被当作立即数,可以当作数组初始化下标
c语言里用const修饰的值可以不初始化,只是之后再没有机会对这个const修饰的变量赋值了。因此我们可以总结出c语言里const定义的常变量和一般变量的区别很小,只是常变量定义后不能作为左值存在。但其真身,或者说是编译方式,和普通变量是一样的。
然而c++里的const修饰的量必须初始化,否则编译无法通过,即在编译的时候把使用const修饰的量都替换为其的值,因此就能作为数组下标,因为编译时,编译器看到的下标并非const 定义的量的名字,而是它对应的值的立即数。
3.引用
引用是c++的一种新类型,通常表示为 数据类型+&;&单独去表达地址。
如 int& b=a;
引用就是被引用量的别名,如果改变b的值,同样也会改变a的值。
(1).
我们来看看引用的底层汇编究竟是什么
int a=10;
00ED439E mov dword ptr [a],0Ah
int &b=a;
00ED43A5 lea eax,[a]
00ED43A8 mov dword ptr [b],eax
可以看到b对a引用,实际上先让eax存放了a的地址,然后再将eax存放的a的地址赋给了b。这不就是个指针做的事情吗。我们再看看指针的汇编是什么样的。
int a=10;
012D439E mov dword ptr [a],0Ah
int *p=&a;
012D43A5 lea eax,[a]
012D43A8 mov dword ptr [p],eax
可以看到指针的汇编和引用的汇编原理是一模一样的。所以说引用其实就是被包装了的指针,不过每次使用引用时都其实都自动做了相当于指针解引用的操作。
(2)引用是要开辟内存的
引用得本质是指针,指针占四个字节
(3)引用数值指针
引用一纬数组int arr[10]={0};
就相当于对int *arr 数组指针进行引用
我们看整形引用是
int &b=int a;
b实际上对a取地址,int *b=&a 只不过&和*都掩盖了,然后在b引用名前紧跟了一个&引用类型
对数组即为对*arr取地址
按上面的推,是不是b其实相当于一个数组指针,对arr数组指针取地址
int (*b)[10]=&arr;
把*用&替代即为
int (&b)[10]=arr;
4.const和指针的结合用法
(1)const和指针
一级指针
Int a=10;
Int *p=&a;
其中const修饰第二句可以这样2种修饰
即int const *p 和int * const p
前者修饰*p,意味着不能改变p解引用后的值,即不能通过解引用p去修改p指向的内存的值。
后者修饰p,意味着p是常量,即可以通过p改变p指向的内存的值,但并不能改变p这个指针本身的值,即p的指向不能改变。
如果int a定义为 const int a;那么这个p只能定义成int const *p;
因为const int a代表不能直接或间接的对a修改,直接就是直接修改a,当然是不行的。间接呢?间接就是把a的地址或者引用泄露出去,让其他高权限的指针通过解引用进行修改。这种显然不符合我们对const的要求,编译器是要杜绝的。
还有一种情况就是这样的。
Int a=10;
Const int *p1=&a;
Int *p2=p1;
a是可以修改的,然后定义了一个const指针p1,它表示不能通过p1修改a的值,这属于权限缩小,当然是没有错误的。
可是第三句int *p2=p1;却是不对的,那是为什么?
首先可以通过权限来判断,第三句相当于把低权限的指针p1让高权限的指针p2使用,这是权限放大,显然有误。
可是有人会疑问,a不是可以修改呢?P2权限大修改a也不影响最终结果啊。
实际上是这样的。编译器在读到Const int *p1=&a这时已经认为p1的指向是个const int类型了,之后再和p1相等指针都应该是const int *类型,如果改成下面这种语序,表达的意思其实和上面一样,但能通过编译
Int a=10;
Int *p2=&a;
Const int *p1=&a;
二级指针和const 中需要注意下面这一种情况,和上面的很像。
Int a=10;
Const Int *p=&a;
Int **pp=&p;
这样是编译无法通过的。和
Int a=10;
Const int *p1=&a;
Int *p2=p1;
比,就是第三句不同,前者是Int **p=&p;后者是Int *p2=p1;
就是本来把p1赋值给另一个一级指针p2,变成了一个二级指针指向p。
为什么会编译不通过呢。上面也说了Const int *p=&a;
这句编译器读完后,就认为p1指向的是个const int 类型了,int **pp指向const int *p就会权限扩大,肯定就会失败。虽然 我们想着**pp修改a,a明明可以修改啊,你可以想成编译器并没有记忆力,先到int a了不会记住a的权限,只会记住Const int *p中p的属性,即使pp和a有合理的关联,但无法通过p这关。也就是常说的间接修改。这也算编译器怕你违反 它认为的规则 的一种预防吧。