C/C++相互调用

C调用C++使用extern "C" 主要是因为C编译器编译函数时不带参数的类型信息,只包含函数的符号名字。

如 int foo( float x ), C编译器会将此函数编译成类似_foo的符号,C连接器只要找到了调用函数的符号,就认为连接成功。而C++编译器为了实现函数重载,会在编译时带上函数的参数信息。如它可以把上面的函数编译成类似于_foo_float这样的符号。

所以,C调用C++,使用extern "C"则是告诉编译器依照C的方式来编译封装接口,当然接口函数里面的C++语法还是按C++方式编译。如:

// C++ Code

extern "C" int foo( int x );

int foo( int x )

{ //……}
这样,编译器会将foo函数编译成类似_foo符号,而不会编译成类似_foo_int符号。

则C可以这样调用C++函数

// C Code

int foo( int x );

void cc( int x )

{ foo( x ); //……}

如果想调用重载的C++函数,则须封装单独的接口共C调用。

如:

// C++ Code

void foo( int x );

void foo( float x );

extern "C" void foo_i( int x ){ foo( x );}

extern "C" void foo_f( float x ){ foo( x );}

则C中可这样调用

// C Code

void foo_i( int x );

void foo_f( float x );

void ccc( int x1, float x2 )

{ foo_i( x1 );

foo_f( x2 ); // ……}

而C++调用C,extern "C" 的作用是:让C++连接器找调用函数的符号时采用C的方式 如:

// C Code

void foo( int x );

C++这样调用C函数

// C++ Code

extern "C" void foo( int x );

就是让C++连接器能过类似于_foo来查找此函数,而非类似于_foo_int这样的符号。




       在实际工作中可能经常要进行C和C++的混合编程,C++调用C语言的代码通常都比较容易,但也有一些细节需要注意。C要调用C++的代码就略为麻烦一些,因为C不支持面向对象的特征。

首先我们来看一下C++调用C语言的代码。要让你的C代码既能被C代码又能被C++调用虽说容易,但是还是有需要注意的地方。现有三个文件分别如下:
/* file TestC.h */
#ifndef TESTC_H
#define TESTC_H
 
#ifdef __cplusplus
extern "C" {
#endif
 
int add(int a, int b);
      
#ifdef __cplusplus
}
#endif
 
#endif /* TESTC_H */
 
/* file TestC.c */
 
#include "TestC.h"
 
int add(int a, int b)
{
    return (a + b);
}
 
/* file TestCpp.cpp */
#include "stdio.h"
#include "TestC.h"
 
int main()
{
       printf("add = %d/n", add(2, 5));
      
       return 0;
}
说明:
file TestC.h是C的头文件,file TestC.c是其实现文件,file TestCpp.cpp是调用C函数的C++文件。
文件TestC.h中的TESTC_H定义是为了头文件保护,” #ifdef __cplusplus”这个不能缺少,你可以去查看C的标准库头文件中都有这个,如”stdio.h”。有了这个宏编译器就知道现在是C还是C++在调用它。
为什么要区分C与C++调用呢?其深层次原因是因为C和C++编译器在编译和链接时对于函数的处理不一样。C++为了支持函数重载在编译时会加入函数参数及类型信息。如上面的add方法,C编译器编译后在符号库中的名字为_add,而C++编译器则会产生像_add_int_int之类的名字。C++正是依靠这种机制实现了函数的重载。
extern关键字表示将函数或变量声明为全局类型,与之相对应的是static。static限定函数或变量的作用域为本文件。extern还有一个作用就是与”C”连在一起使用,即extern “C”通知编译器将extern “C”所包含的代码按照C的方式编译和链接。
 
下面我们就来看看如何在C语言中使用C++的代码(包括C++类的方法)。为了简单起见,我将类的定义和实现放在一个文件中(通常应该是将分别放在.h和.cpp文件中)。自定义类文件(这里省略了头文件保护等其它细节)如下:
//* file TestClass.h */
 
class HJH
{
public:
    int add(int a, int b)
       {
              return (a + b);
       }
};

将C++类封装为C函数的文件(为了简略也将声明和实现放在了同一个文件中)如下:
/* file TestCpp.cpp */
 
#include "TestClass.h"
 
extern "C" int add_cpp(int a, int b);
 
int add_cpp(int a, int b)
{
       HJH hjh;
 
       return hjh.add(a, b);      
}
 
实际调用C++代码的C文件如下:
/*file TestC.c */
#include "stdio.h"
 
extern int add_cpp(int a, int b);
 
int main()
{
       printf("add_cpp = %d/n", add_cpp(2, 5));
      
       return 0;
}

上面的过程很清晰,就是用一个函数将C++类的使用封装起来,然后将它外部声明为C函数就可以了。
文件TestClass.h定义并实现了一个类,该类只有一个add方法。文件TestCpp.cpp定义并实现了一个函数add_cpp,函数中定义了一个HJH类对象并调用了该对象的add方法。然后将add_cpp函数进行外部声明为C。
TestC.c文件中为了使用add_cpp函数,也需要进行外部声明。这是为了通知编译器说明这个函数是在其他文件中实现(注意在C文件中的extern后面不可加”C”)。当这三个文件一起编译链接时,编译器就可以找到add_cpp的具体实现。
以上代码均在Visual C++6.0环境下编译通过并运行。如果有疑问请留言或E-mail: hjhinternet@163.com

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值