我可以在C程序中使用用C++创建的共享库吗
Can I use shared library created in C++ in a C program?
我正在使用C创建程序。但是,我需要使用许多只有C++的API库。那么,我有可能在C++中创建一个共享对象,然后使用C访问它的功能吗?
- 我传递和返回的唯一数据将是C兼容的数据类型
- 转换或迁移到cpp在这里不是一个选项
如果无法将这些代码接口,如何将信息从C++代码转换为C代码?我试着从C调用C++函数,但当我包含<string>
时,在链接过程中会出现错误。所以当我从C调用C++函数时,我应该只使用与C编译器兼容的代码吗?
C++标头cppfile.hpp
#ifndef CPPFILE_H
#define CPPFILE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int myfunction(const char *filename);
#ifdef __cplusplus
}
#endif
#endif
C++文件cppfile.cpp
#include "cppfile.hpp"
#include <string>
int myfunction(const char *filename) {
String S(filename);
return 0;
}
C文件cmain.C
#include "cppfile.hpp"
int main(int argc, char **argv)
{
int i = myfunction(argv[1]);
printf("%dn", i);
return 0;
}
编译:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
您想要更像这样的东西(这里我将使用一个更有意义的例子):
C/C++标头-动物.h
#ifndef ANIMAL_H
#define ANIMAL_H
#ifdef __cplusplus
class Animal {
public:
Animal() : age(0), height(0) {}
Animal(int age, float height) : age(age), height(height) {}
virtual ~Animal() {}
int getAge();
void setAge(int new_age);
float getHeight();
void setHeight(float new_height);
private:
int age;
float height; // in metres!
};
#endif /* __cplusplus */
#ifdef __cplusplus
extern "C" {
#endif
struct animal; // a nice opaque type
struct animal *animal_create();
struct animal *animal_create_init(int age, float height);
void animal_destroy(struct animal *a);
void animal_setage(struct animal *a, int new_age);
void animal_setheight(struct animal *a, float new_height);
int animal_getage(struct animal *a);
float animal_getheight(struct animal *a);
#ifdef __cplusplus
}
#endif
#endif /* ANIMAL_H */
C++动物实现文件-animal.cpp
#include "animal.h"
#define TO_CPP(a) (reinterpret_cast<Animal*>(a))
#define TO_C(a) (reinterpret_cast<animal*>(a))
void Animal::setAge(int new_age) { this->age = new_age; }
int Animal::getAge() { return this->age; }
void Animal::setHeight(float new_height) { this->height = new_height; }
float Animal::getHeight() { return this->height; }
animal *animal_create() {
animal *a = TO_C(new Animal);
return a;
}
animal *animal_create_init(int age, float height) {
animal *a = TO_C(new Animal(age, height));
return a;
}
void animal_destroy(animal *a) {
delete TO_CPP(a);
}
void animal_setage(animal *a, int new_age) {
TO_CPP(a)->setAge(new_age);
}
void animal_setheight(animal *a, float new_height) {
TO_CPP(a)->setHeight(new_height);
}
int animal_getage(animal *a) {
TO_CPP(a)->getAge();
}
float animal_getheight(animal *a) {
TO_CPP(a)->getHeight();
}
C客户端代码-main.C
#include "animal.h"
#include <stdio.h>
int main()
{
// 6'0" 25yo (perhaps a human? :P)
struct animal *a = animal_create(25, 1.83);
animal_setage(a, 26); // birthday
printf("Age: %dnHeight: %f", animal_getage(a), animal_getheight(a));
animal_destroy(a);
return 0;
}
C++客户端代码-main.cpp
#include "animal.h"
#include <iostream>
int main()
{
// 6'0" 25yo (perhaps a human? :P)
Animal* a = new Animal(25, 1.83);
a->setAge(26); // birthday
std::cout << "Age: " << a->getAge() << std::endl;
std::cout << "Height: " << a->getHeight();
delete a;
return 0;
}
因此,在编译库时,使用C++编译器编译animal.cpp
。然后,您可以使用C代码链接到它,并使用animal_xxx
函数。
注意struct animal
和Animal
的使用。CCD_ 6是一个正常的C++类型。这正是它看起来的样子。而struct animal
则是一种"不透明"类型。这意味着你的C程序可以看到它在那里,也可以有一个,但它不知道里面有什么。它只知道它有一个函数,它需要一个struct animal*
。
在一个真正的库中,你会想要有用于内存分配的自定义点。因此,假设这是库libjungle
,您可能至少需要具有合理默认值的jungle_setmalloc
和jungle_setfree
。然后,您可以在libjungle
的C++代码中设置全局new
和delete
,以使用这些用户定义的函数。
这是完全可能的。以下是如何快速:1.)您有一个带有C API的头.h,它不包括任何Cplusness。
#ifndef MIXEDCCPP_H
#define MIXEDCCPP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h> // Any C-compatible headers will go here.
// C API goes here. C Functions can't contain any CPPiness.
void myclass_setName( void *pClassObj, const char *pName, int nameLen );
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
// Stuff that is only compatible with CPP goes here
// __cplusplus section won't get processed while compiling C files.
#include <vector> // CPP headers.
class MyClass {
// Classes etc.
};
#endif // #ifdef __cplusplus
#endif // MIXEDCCPP_H
然后在.cpp中,您只需创建一些C-API函数,甚至可以在其中包含cpp:
#include "mixedccpp.h"
extern "C" {
// C API goes here. C Functions can't contain any CPPiness in their prototypes.
void myclass_setName( void *pClassObj, const char *pName, int nameLen )
{
// But CPP knowledge can go inside the function - no problem, since this is a CPP file.
MyClass *pMyClass = static_cast<MyClass *>(pClassObj);
pMyClass->setName( pName, nameLen );
}
} // #extern "C"
// CPP Stuff goes here... or vice-versa.
在您的情况下,实际上不需要在头中声明任何CPP代码,因为您正在调用外部库。但是您需要在CPP文件中创建C兼容函数,该函数可以调用CPP库。对于那些需要从C文件调用的函数,请使用extern"C",然后使用C结构而不是类,如果需要类,请使用void*指向它们,然后在需要访问它们时,从C函数将它们强制转换回它们的类。标准makefile应该能够很好地编译它,假设它将.cpp文件编译为.cpp并理解外部"C"{}
您的C代码不能使用C++头<string>
。您必须确保C++API中要从C调用的函数声明为extern "C"
(如您所知),并且仅使用C编译器识别的类型(如您已知)。
如果您的任何代码都在C++中,您还需要与C++编译器链接。如果你准备花费大量精力来正确选择加载程序选项,你也可以用其他方法,但只使用C++编译器要简单得多:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
g++ -o cmain cmain.o cppfile.so
当然,你需要:
- 在
cmain.c
中添加#include <stdio.h>
- 在
cppfile.cpp
中使用std::string S(filename);
此外,如果在没有参数的情况下调用程序,则会得到:
$ ./cmain
terminate called throwing an exceptionAbort trap: 6
$ ./cmain x3
0
$
您需要防止误用,即使在测试程序中也是如此。
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 在创建共享库时,是否可以明确地排除某些类
- 为什么从引用创建共享指针会复制对象?
- Android :需要在 c++ NDK 中创建共享首选项对象并存储一些布尔值
- 使用多个标头使用 CMake 创建C++共享库
- 如何从静态c和c++库创建共享c库
- G 在创建共享对象时无法链接库
- 在创建共享对象时,不能使用针对未定义符号的重定位R_X86_64_PC32;使用-fPIC重新编译
- C++:从静态库创建共享对象
- 当我可以创建共享指针时,为什么我不能创建指向数组的唯一指针?
- 我可以在libleveldb.a中找到符号,但是当我创建共享库时,找不到相同的符号。
- 如何在HP-UX中使用GCC创建共享库
- 创建共享_ptr似乎会导致segfault
- 有没有办法使用 WINAPI 或 Embarcadero C++ Builder XE 创建共享目录/文件夹
- 使用openmp创建共享锁
- 如何使用 ld 创建共享库
- 如何在 OSX 上使用 glfw3 在 OpenGL 和 OpenCL 之间创建共享上下文
- 如何在linux x64上创建共享库对象,该对象内部使用C++异常,并且可以在旧平台上运行
- 是否可以使用 std::shared_ptr 创建共享对象池,并在没有自定义析构函数的情况下创建weak_ptr
- 如何在 C++ 中为安卓和 iOS 创建共享库