同一个工程中c++语言与c语言相互调用之处踩的坑否则报函数未定义,注意如下几点:


  • c编译器和c++编译器编译同一个函数出来的符号结果是不一样的(因为c++支持重载,比如fun(int a,int b)函数c++编译出来就是fun_int_int,而c编译出来仅是fun),因此无法相互调用
  • extern "C"{ } 是c++编译器才能识别的关键字,c编译器遇到了会直接报错
  • xx.cpp文件IDE会自动采用c++编译器进行编译,xx.c文件被自动采用c编译器来编译
  • __cplusplus宏是c++编译器内部已经定义的了,而c没有
  • c或者.c++文件这种源码文件想调用一个外部函数,得在自个儿文件内先声明,这样编译器在链接该源码文件与该函数时才知道原来这是个外部函数

extern "C"{ }因此只能在cpp文件中使用(才不会报错),具有两个作用:

一、c++文件中调用c文件内的函数C_fun()时:由于C_fun()函数是用c编译器编译的(生成目标文件xx.o),因此c++中调用时,要在c++文件中先声明外部函数或者变量,作用是告诉c++编译器,extern "C"{ }里面的函数是c编译器按照c语言规则编译的,那我c++文件调用了这个函数,在将它链接时候就以c的规则在xx.o里找到它来链接。(否则,以c++规则去xx.o里找C_fun()函数是找不到的),xx.c++文件编写如下即可

extern "C" {

void C_fun();  //声明这个函数是 先调用文件后面才定义的函数或者是 外部函数

}

int main()

{

C_fun();

}

那么现在有个问题,如果是另一个yy.c文件也想调用c文件内的函数C_fun()时,很明显直接调用即可,因此不需要用extern "C"{ },而且用了会报错。因此yy.c文件编写如下即可:


void C_fun();   //声明这个函数是 先调用文件后面才定义的函数或者是 外部函数

int main()

{

C_fun();

}



.h头文件的作用:是把文件内容直接插进包含该文件的.c或者.c++文件的那儿,相当于是宏替换。因此有函数需要被外部调用的源码文件(c或者.c++文件写的算法库函数等)就直接把会被外部调用函数的声明写在一个对应同名的.h文件内,这样每个源码文件直接包含此头文件即可,但是c文件内定义的函数可能被c++文件或者另一个c文件调用,因此结合上面所说知识,为了不报错,对应的.h文件编写如下即可:


#ifdef __cplusplus   //这样的话只有c++文件内包含了这个头文件(即插入了这段代码进去)extern "C" { 才生效(因为c++文件IDE是自动转为c++编译器编译了),而另一个c文件内包含了该段内容,就仅仅是看到void C_fun(); 这句代码,即常规的声明。这样就解决了这个c++或另一个c调c内函数的问题

extern "C" { 

#endif

void C_fun();  //声明这个函数是 先调用文件后面才定义的函数或者是 外部函数

#ifdef __cplusplus

}

#endif


二、c文件中调用c++文件内的函数Cpp_fun()时:Cpp_fun()是定义在c++文件中,因此已经在c++文件中进行了编译(各个源文件是多核并行编译的,不分先后),当然就是采用c++编译器的啦。按同理,.c文件应该如下写法:


extern "C++" {

void Cpp_fun();  //声明这个函数是 先调用文件后面才定义的函数或者是 外部函数

}

int main()

{

C_fun();

}

这样是不行的。在编译该.c文件时,IDE转为c编译器对其进行编译,然而,c编译器功能少呀(因为先有c,再有c++),没法兼容后来者c++的特性呀(重载函数编译出的符号规则,叫c编译器去链接它也不会链接呀),那怎么办呢?只能让c++编译器妥协了(谁叫你功能更强大,完全支持c编译规则,而且你是新秀,得让着老前辈c编译器嘛),因此c++文件中编译Cpp_fun()时,只要告诉c++编译器你给我用c的规则来编译Cpp_fun()这个函数(这样生成的目标文件.o文件中该函数的符号就是c规则,也就是说这样的函数定义时不能有重载现象,那这样指定用c编译,肯定就同名冲突的报错啦),这样别的c文件也好(相当于是c文件调外部c语言规则函数,和上述作用一同理),c++文件也罢(相当于c++调外部c语言规则函数,和上述作用一同理),都能调这个函数了。其编译规则指定(这个是正在编译时刻起作用的,和上面的链接寻找符号时候起作用是不同的,extern"C"总共也就是这两个作用)也是用extern"C"{},要在c++文件内一定得有声明才可以,在别的引用该函数得源码文件内得extern"C"{}已经无法改变当初Cpp_fun()的编译规则,只能是改变当前源码文件的链接规则罢了,因此仅别的文件加这个extern "C"不行。那么正确的应该如下写法.c++文件:


extern "C"   //告诉C+++编译器,扩号里按照C的命名规则编译

{  

void Cpp_fun();

}

void CPP_fun()  //其定义实现过程

{

    .....

}

此时, Cpp_fun()函数已经是c语言规则编译结果函数了,别的源码文件(c或c++)调用该函数,就跟上面作用一一样,c调用它那就直接声明,c++调用它那就加extern "C"声明。因此可以统一编写为.h头文件:


#ifdef __cplusplus   

extern "C" { 

#endif

void Cpp_fun();  

#ifdef __cplusplus

}

#endif

定义实现该函数的c++文件包含一下该头文件,调用该函数的源文件(c或c++)也包含一下该头文件即可解决。


ps:网上​​博客​​说在c++文件中指定Cpp_fun()编译规则时,头文件要加extern"C"{},代码中也要加,我在qt中试了一下,代码中不加也没关系,不会报错,c++文件内容如下:

extern "C"   //告诉C+++编译器,扩号里按照C的命名规则编译

{  

void Cpp_fun();

}


extern "C"  // 这句不用加,不会报错,加了当然也不报错

{

void CPP_fun()  //其定义实现过程

{

    .....

}

}