C与C++的区别与相互调用

一:两者的区别
  1. 从语言本身的角度:全面兼容C语言;支持面向对象编程;C++的可重用性、可扩充性以及可维护性较好。是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 所以C与C++的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“ 设计这个概念已经被融入到C++之中 ”
  2. 从语言的结构:在编写C语言程序的时候,程序的结构主要包括预处理程序、自定义类型说明、常量定义、函数定义以及主函数定义几大部分;在编写C++语言程序的时候,从面向对象的角度,程序的结构主要包括类的定义和使用两个主要组成部分。
  3. 从处理输入输出的角度:C语言中使用scanf()函数实现格式化输入,使用printf()函数实现格式化输出。如果输入和输出函数中格式化类型与实际类型不符时,C编译器无法检查出错误,但是程序运行时会出现问题。而C++采用了流的形式来控制输入和输出操作,cin为标准输入流,cout为标准输出流;它们都为对对象来使用,正是一切皆对象的理念。即使输入输出语句中定义了不同类型的数据,在编译和执行过程中将不会出现任何错误信息。
  4. 从局部变量的声明方式看:在C语言中,全局变量必须声明在所有函数之前,局部变量在函数的内部必须声明在所有可执行语句之前;C++中允许在代码模块中的任意位置对局部变量进行声明。
  5. 从函数重载的角度:C语言中不存在函数重载的概念,不允许出现名称相同的函数;C++允许重载函数,即对于函数参数类型不同、参数个数不同或者参数类型和个数都不同的情况。
  6. 从处理动态存储分配角度:C语言中使用malloc()函数分配动态内存空间,使用free()函数释放动态内存空间;这仅仅是用于分配内存空间。由于malloc函数返回的是void型指针,因而需要强制转换类型。C++则采用new和delete操作符,new可以自动计算所要分配的内存大小,并返回正确的指针类型;除了分配存储空间之外,new 自动调用构造函数。
  7. 强制类型转换角度:C语言必须将类型括起来,C++可以将变量括起来。比如int(a)在C++中是正确的,但是在C语言中是错误的,必须写为(int)a。
  8. 从定义结构体的角度:在C中声明struct变量要这么写:struct mystruct a;  在C++中前面不用加struct:mystruct a; 此外,在C++中,struct结构体支持成员函数的定义,C中不行。另外要注意的是,C++中成员函数的默认访问说明符为public,这一点和类不同,类的默认访问说明符为private.
  9. BOOL类型的角度:C++中有bool(或boolean类型);C中可没有这样的bool类型,均为数值类型!需要注意的是真为非零,假的数值为0。
  10. 赋值语言的角度: C语言中的赋值只有一中即:=;  C++中除了使用=外,还可以使用()。例如:int  x(5);就等于: int x=5; 我想这种写法是给C++中对象初始化时为了对基类的属性以及常量来进行赋值。
  11. 运算符&的角度:&运算符最基本的含义是取地址,C和C++中都支持这一语法。但在C++中&还可以表示引用。有了引用的概念后函数调用可以作为左值。
  12. const的角度:在C++的类函数中,函数可以声名是可以用const,表示这个函数没有改变类中的任何属性。而在C中,不能有这样的生明。
  13. extern的角度:在C语言的某些版本中,可以在程序中多次使用一个全局变量而无需使用extern说明符。但在C++中除定义全局变量外,在其他模块使用应先用extern生明。
  14. 从void指针的角度:在C语言中void指针可以赋给任何类型的指针,但在C++中,却不行,但可以先进行强制数据类型转换,再进行赋值。
  15. 从STL的角度:标准C++拥有强大的标准容器类,对很多问题管理更加方便些。
  16. 异常处理的角度:C++能够对异常进行处理,而不仅仅像C语言那样去报告一个问题。
  17. 从运算符重载的角度:C++支持运算符重载,这样在设计程序的思想更加符合解决现实的世界问题的思路。
  18. 从内联函数的角度:为了解决函数在调用过程中产生的栈开销,C++支持内联函数。
二:两者之间的相互调用
  1. 如果C++程序要调用已经编译好的C函数,如何调用:假设某个C函数的声明void foo (int x, int y); 该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++程序不能直接调用C函数。C++提供了一个C连接交换指定符号 extern “C”来解决这个问题。extern“C” { void foo(intx,inty); }或者extern“C”{ #include“myheader.h” }。这就告诉C++编译译器,函数foo是个C连接,应该到库中找名字_foo而不是找_foo_int_int。另外说明一点:C++编译器开发商已经对C标准库的头文件作了extern“C”处理,所以我们可以用#include在C++程序中直接引用这些头文件。
  2. 如何理解 extern"C":extern"C"包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern” 的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。被extern"C"限定的函数或变量是extern类型的;extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:extern int a; 仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern“C”修饰。被extern"C"修饰的变量和函数是按照C语言方式编译和连接的;未加extern“C”声明时的编译方式,首先看看C++编译器中对类似C的函数是怎样编译的。首先看看C++编译器中对类似C的函数是怎样编译的。作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:void foo (int x,int y); 该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”。_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数voidfoo(intx,inty)与voidfoo(intx,floaty)编译生成的符号是不相同的,后者为_foo_int_float。同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。所以,可以用一句话概括extern“C”这个声明的真实目的。实现C++与C及其它语言的混合编程。
  3. extern "C"的惯用法:在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern"C"时会出现编译语法错误。因此,我们经常会做如下处理:
    #ifdef _cplusplus
      #define GENERAL_EXTERN extern“C”
    #elseif
      #define GENERAL_EXTERN extern
    #endif
    在使用的时候,GENERAL_EXTERN int foo (int x, int y) 代替extern "C" int foo (int x, int y); 说明:使用条件编译,可以有选择题告诉编译器,采用哪种方式编译。如果使用的是C++编译器,那么采用extern“C”(实现混合编程);如果使用的是C编译器,那么采用extern(编译不会出错)。
  4. C语言应用C++:在C中引用C++语言中的函数和变量时,C++的头文件需添加extern"C",但是在C语言中不能直接引用声明了extern"C"的该头文件,应该仅将C文件中将C++中定义的extern"C"函数声明为extern类型。
  5. 如何实现C调用C++接口库:C一般不能直接调用C++函数库,需要将C++库封装成C接口后,才可以使用C调用之。所以要了解C封装C++接口策略。
  6. 对由__cplusplus和extern "C"组成的C、C++编译器编译标准C函数的通用写法的理解:由于C++编译器需要支持函数的重载,会改变函数的名称,因此dll的导出函数通常是标准C定义的。这就使得C和C++的互相调用变得很常见。但是有时可能又会直接用C来调用,不想重新写代码,让标准C编写的dll函数定义在C和C++编译器下都能编译通过,通常会使用以下的格式:(这个格式在很多成熟的代码中很常见
    #ifdefined (__cplusplus)
      extern"C"{
    #endif
       //在这里写标准C程序,例如dll导出函数的定义
    #ifdef__cplusplus
      }
    #endif

你可能感兴趣的:(C语言)