• C和C++相互调用


    在项目中融合C和C++有时是不可避免的,在调用对方的功能函数的时候,或许会出现这样那样的问题。
    近来在主程序是C语言,而调用C++功能函数的时候,C++的*.h头文件都能找到,功能函数也都定义了,最重要的是,单独编译C++的时候完全没有问题,
    但当用主程序的C调用C++的功能函数时总是提示该函数未定义(undefined)。这是什么问题?如何解决?

    关键点在这里:我们就靠在C++的*.h和*.cpp的头尾加入下面代码才得以解决问题。

    #ifdef __cplusplus
    extern "C" {
    #endif
    //一段代码
    #ifdef __cplusplus
    }
    #endif

    1、#ifdef _cplusplus/#endif _cplusplus及发散
    其中 __cplusplus是cpp中的自定义宏,很明显#ifdef/#endif、#ifndef/#endif用于条件编译,
    #ifdef _cplusplus/#endif _cplusplus——表示如果定义了宏_cplusplus,就执行#ifdef/#endif之间的语句,否则就不执行。
    上面的代码的含义是 : 如果这是一段cpp的代码,那么加入extern "C"{ 和 } 处理其中的代码。
    在这里为什么需要#ifdef _cplusplus/#endif _cplusplus呢?因为C语言中不支持extern "C"声明,如果你明白extern "C"的作用就知道在C中也没有必要这样做,这就是条件编译的作用!在.c文件中包含了extern "C"时会出现编译时错误。

    2、extern "C"
    extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
    通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。
    与extern对应的关键字是 static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
    在C++源文件中的语句前面加上extern "C",表明它按照类C的编译和连接规约来编译和连接,而不是C++的编译的连接规约。这样在类C的代码中就可以调用C++的函数or变量等。
    还有要说明的是,extern "C"指令仅指定编译和连接规约,但不影响语义。例如在函数声明中,指定了extern "C",仍然要遵守C++的类型检测、参数转换规则。

    3、C和C++互相调用
    要明白为何使用extern "C",还得从cpp中对函数的重载处理开始说起。
    在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等。
    而在C中,只是简单的函数名字而已,不会加入其他的信息。也就是说,C++和C对产生的函数名字的处理是不一样的。
    加入 extern "C" 声明的目的是解决C与C++的相互调用的问题。

    3.1、C++的编译和连接
    C++是一个面向对象语言(虽不是纯粹的面向对象语言),它支持函数的重载,重载这个特性给我们带来了很大的便利。为了支持函数重载的这个特性,C++编译器实际上将下面这些重载函数:
    void print(int i);
    void print(char c);
    void print(float f);
    void print(char* s);
    编译为:
    _print_int
    _print_char
    _print_float
    _pirnt_string
    这样的函数名,来唯一标识每个函数。注:不同的编译器实现可能不一样,但是都是利用这种机制。所以当连接是调用print(3)时,它会去查找_print_int(3)这样的函数。
    下面说个题外话,正是因为这点,重载被认为不是多态,多态是运行时动态绑定(“一种接口多种实现”),如果硬要认为重载是多态,它顶多是编译时“多态”。
    C++中的变量,编译也类似,如全局变量可能编译g_xx,类变量编译为c_xx等。连接是也是按照这种机制去查找相应的变量。

    3.2、C的编译和连接
    C语言中并没有重载和类这些特性,故并不像C++那样print(int i),会被编译为_print_int,而是直接编译为_print等。因此如果直接在C++中调用C的函数会失败,因为连接是调用C中的print(3)时,它会去找_print_int(3)。因此extern "C"的作用就体现出来了。

    3.3、C++中调用C的代码
    假设一个C的头文件cHeader.h中包含一个函数print(int i),为了在C++中能够调用它,必须要加上extern关键字。
    C++程序调用C函数:http://blog.csdn.net/ustcgy/article/details/5063082

    3.4、C中调用C++的代码
    C程序调用C++函数 : http://blog.csdn.net/ustcgy/article/details/5063243


    参考链接:http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html
    http://blog.chinaunix.net/uid-24118190-id-2985318.html

  • 相关阅读:
    简单工厂、工厂方法、抽象工厂
    c#之反射总结
    设计模式Builder(建造者)模式
    c#之委托和事件的区别
    c#之委托总结
    javascript之流程控制 和函数的容易忽略点
    javascript之六种数据类型以及特殊注意点
    Sublime Text 快捷键
    链接中获取文件名
    js 获取当天23点59分59秒 时间戳 (最简单的方法)
  • 原文地址:https://www.cnblogs.com/klcf0220/p/4351765.html
Copyright © 2020-2023  润新知