C与C++区别

1.     inline函数:

           特点:在编译过程中,该函数在函数调用点,就将该函数的代码全部展开,会进行类型的检查。

(1) inline函数是一种更安全的宏:

宏在预处理阶段进行替换,只是单纯的字符串的替换,并不会进行类型检查,宏没有办法调试,inline函数在编译阶段在函数调用点将函数的代码展开,但会进行类型检查,因此称为更安全的替换

(2) inline函数和普通函数的区别:

inline函数没有标准函数栈帧的开辟和回退;

inline函数不产生符号,只能用在本文件当中

(3)   inline函数和static函数的区别:

        1.作用域:inline函数和static函数都是在本文件中可用;

         2.栈帧开辟回退:inline函数没有栈帧的回退,但static函数有栈帧的回退;

         3.符号的产生:inline函数编译后不产生符号,static函数编译时产生符合(local)

 (4) 普通函数和static函数区别:

        static函数只是本文件可见-》即普通函数和static函数产生的符号不同,普通函数产生globle符号,static修饰的产生local符号,连接器只处理globle符号,不会处理local符号。

   

*inline函数只是在release版本起作用;inline函数在debug版本,该版本需要调试,该函数的调用也需要栈帧的开辟和回退,inline函数只是对编译器的一个建议。

====================================================================================================================================

2.     函数的重载:

C语言中--à函数产生符号->由函数名决定

C++中----à函数产生符号->由函数名称+形参类型+形参个数

C++构成函数的重载:

1.函数名相同,参数列表不同,不能仅通过返回值不同进行函数的重载(因为函数产生符号,和函数的返回值没有关系)

 2.重载必须处于同一个作用域;

3.对实参的值是否有影响(const  /volatile */&可以作为函数重载的前提条件)

如:void func(int  *a)与void  func(const  int *a)就可以构成重载

Volatile关键字作用:

1.  防止编译器对汇编指令进行顺序上的优化:

防止编译器对指令顺序的调优----使用volatile

防止程序运行时CPU对指令顺序上的调优-------barrier()

2.  防止寄存器存储变量的副本值:

主要应用于多线程程序中

如:int a = 10;

     void func()

     {

        a = 20;

}

Thread1    func();

Thread2

{int b =a;//mov  eax,dword  ptr[a]

mov dword ptr[b],eax

 Int c = a;// mov dword ptr[c],eax!!!!

}

====================================================================================================================================

3.     Const

         用const修饰的量不能再被修改

(1)在C中的const:经const修饰后不能再被修改,const修饰的量并不是一定要初始化;但若不初始化后期也不可以再被赋值----à在c中const修饰的量是一个常变量而不是常量。

在C中const修饰的常变量和普通的变量唯一区别

常变量并定义以后,不可以再作为左值。(即const修饰的常变量也是globel的)

(2)在C++中的const:

(定义时初始化,常量->常变量,作用域是local的)

1.必须要初始化(和c不同)

2.在C++中,const修饰的量是常量(明确的初始值)

3.在C++中,const的编译规则(和c不同):所有使用常量名字的地方全部替换成常量的初始值(类似于宏,inline函数)

4.Const修饰的常量什么时候变成常变量?

当引用一个编译阶段不明确的值的时候,会变成常变量

如:int main()

{       Int b = 20;

const  int a = b;//成为一个常变量            

int  arr[a] = {0};//  a是一个常变量, 编译出错

}

5.在C++中,const修饰的量如:constint data = 20;生成的符号都是local的,即当前文件可见,不可以在其他文件使用(可以在const修饰的常量的定义处,加extern使生成的符号变成global)

====================================================================================================================================

4.     引用&:

(1)     引用不参与类型;

(2)     定义引用和定义指针相同,同样需要开辟内存;

(3)     从汇编指令来看,定义一个引用变量和指针变量以及分别给变量赋值,是一模一样的。从底层来说,指针和引用是一样的,但从语法上来说并不相同;

引用规则:

(1)必须初始化;

(2)初始化的值必须要能够取地址(若右值不能取地址,需要加const产生临时变量);

(3)一经引用不能改变;

(4)访问引用变量(由于会自动解引用),永远访问的都是它所引用的内存,引用会比指针更安全一些,因为指针可能会出现无效指针。

Q:定义引用变量是否开辟内存?开辟内存。

A:之所以有些书上说引用变量没有内存,是因为引用变量会自动解引用,访问引用变量时访问的是所引用的内存,而不会是引用变量开辟的内存。

5.     Const和一级指针的结合:

const  int  *p;(*p不能修改,p可以修改)

int  const  *p;(*p不能修改,p可以修改)

int *const  p;(*p可以修改,p不能改)

const int *const p; (*p可以修改,p不能改)

const int *-->int *  错误!

Int *------->const int * 正确;

如:

   int a = 10;

   const  int *p = &a;//正确

   int *q = p;  //错误,

由于p既可以指向const int a = 10;也可以指向int a = 10;所以q并不知道是变量还是常量,所以错误。

Const如没有修饰*/&时,并不考虑const

如:

Void func(int  a)

Void func(const int a)//不可以构成重载。

====================================================================================================================================

6.     Const和引用的结合:常引用

&必须要和引用变量写在一起,常量只能用常引用:

const &引用常量:可寻址的常量和不可寻址常量(产生一个临时量)

const只有结合&时会产生临时量,和*结合不会产生临时量。

例子:

const  int a =10;const  int &b = a;

int &a = 10;(错误)

引用必须初始化,并且初始化不能是一个立即数,因为无法取地址

const int &a = 10;(正确)

加上const,产生了一个临时量,a中的地址是临时量的地址。

====================================================================================================================================

7.     Const和二级指针的结合:(见笔记)

8.     动态内存的开辟

malloc---->free             new------>delete

new->malloc:new作用一是开辟内存;二是初始化(内置类型是初始化,自定义类型 调用析构函数)

开辟100个元素的整型数组:

int *p = (int *)malloc(sizeof(int)*100)----->free(p)

int *p = new int[100]//此时不能给数组元素赋值

delete[]p;

new:::

(1)new开辟内存失败,不会返回NULL,而是抛出一个异常:throw bad_alloc();

(2)不抛出异常的版本:int *p = new(nothrow)int(10);此时是判断返回值是否为NULL;

(3)定位new   placement new

char buff[1024] = {0};

char *p = new(buffer)char [100];//在buff上开辟一个100个元素的数组;

开辟内存与初始化分开进行:

Int *p = new int;

P = new(p)int(10);

(4)在堆上开辟常量

const int *p = new const int(4);

cons tint *q = new cosnt int [10]

====================================================================================================================================

9.     C/C++的作用域:

(1)C的作用域:局部作用域,全局作用域;

C++的作用域:

局部作用域,类作用域,

名字空间作用域namespace(全局的名字空间作用域,局部的名字空间作用域)

例:定义一个名字空间,Myname-à定义一个新的作用域

Namespace  Myname(名字不参与编译,不产生符号)

{

}可以定义多个同名的名字空间,编译时会合并;

using  指示符

usingMyname :: gdata;

usingnamespace Myname;表示将Myname中所有符号放于全局作用域

usingnamespace std;//表示std名字空间下所有符号放在全局作用域。

====================================================================================================================================

10.   C/C++之间的互相调用

可以看见源代码:

(1)     在.cpp文件中调用.c文件的函数:

产生问题:在.c文件中函数产生的符号和.cpp中产生的符号不同,因为无法编译通过。

解决方法:用extern “c”解决,extern c表示里边的符号都是按照c规则生成,所以生成符号时,按照c产生函数符号

(2)     在.c文件中调用.cpp文件中函数:

产生问题:在.c文件中函数产生的符号和.cpp中产生符号不同,

解决办法:将cpp源码括在“extern “c””中,从而产生的符号和c产生的符号相同,从而.c文件中可以调用.cpp文件中函数。

Q:静态链接和动态链接的区别:静态库(.lib/.a)动态库(.dll/.so)

A:静态链接:生成可执行文件之前就进行链接;占用磁盘空间较多但是速度更快;

  动态链接:程序运行时连接;

不可见源代码(已经是库函数,是可执行文件):

(1)在.cpp文件中调用.c库中的函数:

用c写的.so库,已经是可执行程序,在cpp文件中在声明处加”extern  c”

(2)在.c文件中调用.cpp库中的函数:

由于此时.cpp已经是可执行程序,看不到源代码,因此不能再使用”extern c”括上源代码执行;

解决办法:使用一个中间.cpp文件,包含库,使用”extern c”,即每个临时.cpp文件在自己封装一个接口。

====================================================================================================================================

11.const */&在函数当中的应用

函数的返回值:

(1)<=4  bytes;通过寄存器带回,不产生临时量

(2)>=4  bytes <=8  bytes;通过寄存器带回,不产生临时量

(3)>8bytes;产生临时量

(4)在C++中,当返回一个对象时,不论该对象占用多大内存,都要产生临时量

*函数返回值均为值返回时:

当返回值为内置类型:产生都是寄存器的立即数;

当返回值为自定义类型,当小于等于8字节,指针指向或者引用时,编译器自动产生临时量;

当返回值为一个对象,一律产生临时量,并把临时量的实参传递进来,被调用函数通过访问ebp+8能够访问调用方的临时对象内存地址。

(当函数返回*或者&,再加以讨论)


产生临时量的三种情况:

(1)函数调用之前;(2)函数的return语句;(3)函数调用之后;

*只有const  &时,才有产生临时变量的可能。

 

 

常量与常变量:

在c中:const int a = 10;常变量

在cpp中:const int a = 10;常量,编译时和c也不同,是直接替换的;

          const  int a = b;常变量

 

const  int a = 10;

static int a = 10;

//两个都是本文件可见,生成的符号均为local,若加上“extern”关键字,会使“local”变为“global”

内置类型产生的临时量都是常量(在寄存器中),不可更改;

自定义类型产生的临时量都是变量(在内存中),可以更改;

 

编译器的类型转换(做转换的目的:提高运算的精度):

double<-----------------float

向上转化

unsigned

向上转化

long

向上转化

int  <-----------------------short/char

    





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值