C和C++混合编程FAQ

如何在C++中调用C函数?

仅仅只需要在你的C++代码中将要调用的C函数使用extern进行声明即可,代码如下:

//C++ code
extern "C" void f(int);   //方式一
extern "C" {              //方式二
    int g(double);
    double h();
}

void code(int i,double d)
{
    f(i);
    int ii = g(d);
    double dd = h();
    //........
}

在你的C代码中对上述几个调用的函数就行定义即可,定义如下:

// C code
void f(int i)
{
    /*....*/
}

int g(double d)
{
    /*....*/
}

double h()
{
    /*....*/
}

如何在C中调用C++的函数?

在C++中定义的函数,需要显示的使用extern进行声明,目的是让编译器不对其进行名称mangle,代码如下:

// C++ code:
extern "C" void f(int);
void f(int i)
{
    // ...
}

将上面的代码编译成动态库,然后交由C动态的去调用。下面是在C中如何去调用

/* C code: */
void f(int);
void cc(int i)
{
    f(i);
    /* ... */
}

C调用C++的非成员函数就用如上的方式即可完成,那么C如何去调用C++的类成员函数呢?代码如下:

#include <iostream>
using namespace std;

class C {
public:
    virtual double f(int data)
    {
        cout << "Hello World" << endl;
    }
};

extern "C" C* getC()
{
    return new C();
}

extern "C" void delC(C *data)
{
    delete data;
}

extern "C" double call_C_f(C* p,int i)
{
    return p->f(i);
}

上面定义了一个class C,在这个class C中有我们需要调用的f函数,为了可以调用这个f函数,我们需要提供一个call_c_f这个函数。在这个函数中通过一个具体的对象指针来调用f函数,为了得到对象指针我们提供了getC函数来实例化一个class C,通过指针传递给C函数来使用。下面是C中调用C++的方法:

#include <stdio.h>

struct C;
/* C code: */
double call_C_f(struct C *p, int i);

struct C *getC();
void delC();
void ccc(struct C* p, int i)
{
        double d = call_C_f(p,i);
        /* ... */
}

int main()
{
    struct  C * data = getC();
    ccc(data,10);
    delC(data);
}

首先是对call_C_f,getC,delC三个函数的一个声明,然后就是前向声明class C,因为C中没有class的概念,因此转而使用了struct。首先通过getC得到类C的对象指针,然后传递给call_C_f即可,在使用完成后调用delC释放对象指针。

到此为止C可以调用C++的非成员函数和成员函数了,那么如果去调用C++中的重载函数呢,这个比较简单,代码如下:

// C++ code:
void f(int);
void f(double);
extern "C" void f_i(int i) { f(i); }
extern "C" void f_d(double d) { f(d); }

其实就是给每一个重载的实列都包裹一下即可。就跟C调用C++的非成员函数一个样子。

如何在C++的代码中包含标准C的头文件?

在C++的代码中去包含标准C的头文件基本上不需要做什么特殊的改变,直接#include某个标准库文件即可,比如stdio.h,同样你可以使用
cstdio。代码如下:

/* This is C code that I'm compiling using a C++ compiler */
#include <stdio.h>          /* Nothing unusual in #include line */
int main()
{
  printf("Hello world\n");  /* Nothing unusual in the call either */
  // ...
}

说白了stdio.hcstdio的区别就是一个C版本的,一个是C++版本的,其中C++版本的就是将stdio.h中的内容加入到了C++的std命名空间中,下面的例子中包含了cstdio并引用了std命名空间中的printf函数

// This is C++ code
#include <cstdio>                // Nothing unusual in #include line
int main()
{
  std::printf("Hello world\n");  // Nothing unusual in the call either
  // ...
}

如何在C++代码中包含C非标准库头文件?

如果你要在你的C++代码中包含一些C的非标准库头文件,那么你需要使用extern "C"声明,告诉C++编译器头文件中包含的是C函数。

// This is C++ code
extern "C" {
  // Get declaration for f(int i, char c, float x)
  #include "my-C-code.h"
}
int main()
{
  f(7, 'x', 3.14);   // Note: nothing unusual in the call
  // ...
}

如何修改C的头文件让其可以直接在C++的代码中#include

在C++中为了包含C的非标准库的头文件我们需要将头文件的包含语句放在extern "C"声明中,你一定很奇怪为什么C标准库不需要这样呢?因为C标准库中做了一些手脚,不信你可以看看stdio.h的源码,你会发现在这个头文件的开始有一个__BEGIN_DECLS,结尾有一个__END_DECLS。这两个宏的定义如下:

#if defined(__cplusplus)
       #define __BEGIN_DECLS extern "C" {
       #define __END_DECLS }
       #else
       #define __BEGIN_DECLS
       #define __END_DECLS
#endif

哈哈,看到这里我相信大家应该明白了吧,如果stdio.h被包含在C++的代码中那么__BEGIN_DECLS__END_DECLS就够成了一个extern "C" {}将整个头文件包含在里面了,就等同于extern "C" {#include <stdio.h>}。那么如何改造我们的头文件让其可以直接#include到C++的代码中呢?

Setp1: 将下面的这行放在头文件的开始处,通过判断是否有__cpluscplus判定是被包含在C代码中,还是C++代码中

#ifdef __cplusplus
extern "C" {
#endif

Setp2: 将下面的代码放在头文件的最下面

#ifdef __cpluscplus
}
#endif

到此为止你可以直接将一个非标准库的头文件#include到你的C++代码中了。

如何将C++中的类的对象传递给C函数?

下面是一个完整的示列。

/* This header can be read by both C and C++ compilers */
#ifndef FRED_H
#define FRED_H
#ifdef __cplusplus
  class Fred {
  public:
    Fred();
    void wilma(int);
  private:
    int a_;
  };
#else
  typedef
    struct Fred
      Fred;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
  extern void c_function(Fred*);   /* ANSI C prototypes */
  extern Fred* cplusplus_callback_function(Fred*);
#endif
#ifdef __cplusplus
}
#endif
#endif /*FRED_H*/

上面这个头文件可以被C和C++包含,当被C包含的时候就是一个Fred类和C风格的c_functioncplusplus_callback_function的声明。

// This is C++ code
#include "fred.h"
Fred::Fred() : a_(0) { }
void Fred::wilma(int a) { }
Fred* cplusplus_callback_function(Fred* fred)
{
  fred->wilma(123);
  return fred;
}

这是C++的Fred的类实现.

/* This is C code */
#include "fred.h"
void c_function(Fred* fred)
{
  cplusplus_callback_function(fred);
}

这是一段C代码,包含了fred.h,因此有struct Fred声明,参考如何在C中调用C++的函数?一节。因为C中没有Class所以只能用struct来表示,并且Class在大多数情况下其内存布局都和C中的struct不一样,因此这里只能选择使用指针。

// This is C++ code
#include "fred.h"
int main()
{
  Fred fred;
  c_function(&fred);
  // ...
}

这是一段C++代码,同样包含了fred.h,因此有了class Fread声明,fred.c是其定义, 同时还包含了C风格的c_funcioncplusplus_callback_function声明,参考如何在C++中调用C函数?一节

Reference

How to mix C and C++

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值