在C中调用C++函数

由于C编译器与C++编译器之间的区别十分巨大,因此二者之间不可以直接互相调用各自的函数接口。但是,使用extern "C"可以实现在C代码中调用C++函数的功能,反之亦可。extern "C"告诉C++编译器,将花括号中的代码按照C语言的规则进行编译与链接。

在本篇文章中,笔者展示了利用C代码调用C++接口的一个示例。实现的功能有:C代码获取C++对象指针,并通过对象指针调用对象函数(包括构造函数和析构函数)。
示例分为5个文件:

CppPrint.cpp
CppPrint.h
CWrapper.cpp
CWrapper.h
CallCpp.c

其中CppPrint.cpp中是C++代码的实现,其中用iostream实现了打印Hello world!的功能。这部分的代码没有需要特殊说明的地方,属于一般的C++实现。

/*
 * CppPrint.h
 *
 */
#ifndef CPP_PRINT_H
#define CPP_PRINT_H
#include <string>
class Printer {
public:
    Printer();
    Printer(char* str);
    ~Printer();
    void print();
    void print(char* str);
private:
    std::string mString;
};

#endif // CPP_PRINT_H


/*
 * CppPrint.cpp
 *
 */
#include <iostream>
#include <string>
#include "CppPrint.h"

Printer::Printer()
: mString(""){
    std::cout << "Printer@[" << this << "] is constructed."<< std::endl;
}

Printer::Printer(char* str)
: mString(str) {
    std::cout << "Printer@[" << this << "] is constructed."<< std::endl;
}

Printer::~Printer() {
    std::cout << "Printer@[" << this << "] is destructed."<< std::endl;
}

void Printer::print() {
    std::cout << mString << std::endl;
}

void Printer::print(char* str) {
    if (NULL != str) {
        mString = std::string(str);
    }
    std::cout << mString << std::endl;
}

CWrapper.cpp是利用extern "C"对C++函数的封装。这里有2点需要特殊说明。首先,C++传递给C的对象指针必须以结构体指针的形式存在,否则C语言的编译器会报错。其次,结构体中只可以包含对象指针,不可以直接包含对象示例。若包含的是对象实例,在C代码执行的时候会发生段错误(Segment Fault)。

/*
 * CWrapper.h
 *
 */
#ifndef C_WRAPPER_H
#define C_WRAPPER_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

struct Printer4C;
typedef struct Printer4C* PrinterRef;
PrinterRef getPrinter(char* str);
void print(PrinterRef ref);
void deletePrinter(PrinterRef ref);

#ifdef __cplusplus
}
#endif

#endif // C_WRAPPER_H


/*
 * CWrapper.cpp
 *
 */
#include <iostream>
#include <cstring>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "CppPrint.h"
#include "CWrapper.h"

#ifdef __cplusplus
extern "C" {
#endif

struct Printer4C {
    Printer* obj;
};

PrinterRef getPrinter(char* str) {
    PrinterRef ref = (PrinterRef) malloc(sizeof(struct Printer4C));
    if (NULL == str || strlen(str) <= 0) {
        ref->obj = new Printer("Hello world!");
    } else {
        ref->obj = new Printer(str);
    }
    return ref;
}

void print(PrinterRef ref) {
    ref->obj->print();
}

void deletePrinter(PrinterRef ref) {
    delete ref->obj;
    free(ref);
}

#ifdef __cplusplus
}
#endif

在C文件中获取C++对象指针,并利用对象指针调用成员函数。根据CWrapper的实现,当获取printer时没有传入有效的字符串时,会将打印的内容默认设为“Hello world!”。

/*
 * CallCpp.c
 *
 */
#include "CWrapper.h"

int main() {
    PrinterRef ref1 = getPrinter("");
    PrinterRef ref2 = getPrinter("Welcome!");
    print(ref1);
    print(ref2);
    deletePrinter(ref1);
    deletePrinter(ref2);
}

编译动态库。
$ g++ -fPIC -shared CppPrint.cpp CppPrint.h CWrapper.cpp CWrapper.h -o libCppPrint.so
将libCppPrint.so复制到/usr/lib下。
$ sudo cp libCppPrint.so /usr/lib
编译C代码
$ gcc CallCpp.c -lCppPrint -o CallCpp
执行程序
$ ./CallCpp
控制台输出

Printer@[0x25b0030] is constructed.
Printer@[0x25b00a0] is constructed.
Hello world!
Welcome!
Printer@[0x25b0030] is destructed.
Printer@[0x25b00a0] is destructed.

PS:
实验环境:
Ubuntu 14.04 LTS 64位
gcc与g++的版本均为4.4.7

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值