浅析extern“C”

       extern ”C“的意思是将代码按照C语言的方式编译,是c++中才有的。之所以c++中有这么个东西呢,也是为了解决两种源文件中互相调用的问题。大家应该都知道, c和c++的符号命名规则是不一样的,所以,如果我们在一个c或c++中调用另外一个不同于调用文件类型的,就会有问题。 大家都知道函数名是会生成符号的,我们引用的外部函数肯定也是一个全局类型,我们才能够引用,在编译的时候,我们引用的外部符号都会是*UND*,因为本文件中没有定义,所以在链接前,本文件单独编译时,它无法确定这是什么段里的东西,也无法确定它的符号类型,所以标记为没有定义。而外部符号正是链接过程中符号解析的重点,我们需要将每一个有外部符号引用的地方在链接合并符号表之后,符号解析过程中在符号表中找到有引用符号的定义,它应该就是在.text段,如果没有,那符号解析就会出错,符号解析其实就是符号决议,在这个过程中如果你有外部引用却找不到它的定义,那就会报编译的错误。
       我们可以通过几个场景熟悉一下extern “C”的使用从而也能慢慢感受到它存在的必要性。
       我们将c和c++的互相调用分为两类,一个是c调用c++函数,一个是c++调用c函数,下面我们来详细讲解一下。
       一、c++调用c函数
       sum.c
int sum(int a,int b)
{
      return a+b;
}

       test.cpp
int sum(int a,int b)
{
    int ret=sum(10,20);
}
这样子会产生错误,这是为什么呢?
       因为c编译产生的符号和c++产生符号的命名规则不一样,也就是同样一个函数名,编译之后确是不同的符号名,所以外部引用解析的时候找不到定义,自然会 报链接错误。
        解决方法:1、将c++中sum的声明部分用extern “C”包含进来,这样这个声明还是会按照c的规则编译,所以符号的产生也是按照c的命名规则来,自然在符号表中能找到sum的定义。
        extern “C”
{ int sum(int a,int b);}

       2、_cplusplus 利用宏来解决。
            _cpluplus这个宏只在c++中才有,c中没有,如果此时检测到这个宏有被定义过,则这个文件肯定是c++文件,否则是c文件。
        #ifdef_cplusplus
           extern "C" {
           int sum(int a, int b)
       #endif

       #ifdif_cplusplus
         }
       #endif

      这段代码,能检测到当前如果是c++文件产生的调用的话,就将这个sum声明用c语言编译,如果是c语言编译则不做任何处理,因为这样本来就是c语言,就会调用c的编译器编译,这样就没有任何问题,也不需要处理,也不能处理 ,因为c中没有extern “C”,当然这些的前提是被调用的函数定义是在c中编译的。

    二、c调用c++
           也就是原来文件类型做了一个调换,变成了下面的样子
    sum.cpp
int sum(int a,int b)
{
      return a+b;
}

       test.c
int sum(int a,int b)
{
    int ret=sum(10,20);
}
    最直接的处理方式,是不是将sum.cpp中的sum实现用extern “C”包含起来,但是很遗憾,通常我们使用一个函数的时候,可能就提供了一个接口,你知道它是用c++实现的,可是你不能修改它,因为它只提供了一个函数声明作为接口,告诉你怎么用,那这个时候你说把人家代码定义改成需要extern "C"就不现实了,那怎么办呢?大家学操作系统的时候有没有一种体会,操作系统的设计者是怎样将我们程序员从直接操作计算机物理硬件中解救出来的呢,就是不断增加中间层,不断抽象化,将下一层封装,让上一层使用更加方便,我们这个问题也是利用这种思维解决的,我们可以写一个中间层解决这个问题。
           解决方案:新建一个中间层文件mysum.cpp
         mysum.cpp
extern sum(int a,int b);
//#include "sum.h"                 也是一样的,这里不写sum.c是为了解释如果是其他人写的可能就提供一个.h的文
//件声明作为使用,这样的结果也是一样的,预编译产开将sum.h中的声明包含进来效果一样。

extern "C"
{
     int mysum(int a,int b)
{
     return sum(a,b);
}
}
也可以写成
#ifdef_cplusplus
extern "C" {
int mysum(int a,int b)
{return sum(a,b);}
#ifdef_cplusplus
 }
#endif
这样在test.c中调用的时候声明 int mysum(int a,int b)就行了,因为这个中间文件保证了这个mysum一定是c编译的。
注意:不管我们是用哪种方法,sum的声明不能放在extern “C”中,因为我们知道被调用的函数是c++编写的,所以它生成的符号肯定也是c++的符号生成规则,我们这个中间文件也要写成cpp文件,因为要保证,在声明sum的时候使用c++编译的,生成的也是按照c++符号命名规则生成的,这样链接合并符号表符号决议的时候才不会出错。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值