赞
踩
由于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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。