我可以在 C 程序中使用在 C++ 中创建的共享库吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14917952/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I use shared library created in C++ in a C program?
提问by kicker86
I am creating programs using C. However, I require to use a lot of libraries that have API's only for C++. So, is it possible that I can create a shared object in C++ and then access its functionality using C?
我正在使用 C 创建程序。但是,我需要使用许多具有仅用于 C++ 的 API 的库。那么,我可以在 C++ 中创建一个共享对象,然后使用 C 访问它的功能吗?
- The only data I would be passing and returning would be C compatible data types.
- Converting or migrating to cpp is not an option here.
- 我将传递和返回的唯一数据是与 C 兼容的数据类型。
- 转换或迁移到 cpp 不是这里的选项。
If it is not possible to interface these codes, how do I get information from C++ code to C code?
I tried calling C++ functions from C, but I get errors during linking when I include <string>
. So when I call C++ functions from C, should I only use that code which will be C compiler compatible?
如果无法连接这些代码,我如何从 C++ 代码到 C 代码获取信息?我尝试从 C 调用 C++ 函数,但是当我包含<string>
. 所以当我从 C 调用 C++ 函数时,我应该只使用与 C 编译器兼容的代码吗?
C++ header cppfile.hpp
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++ file cppfile.cpp
C++ 文件 cppfile.cpp
#include "cppfile.hpp"
#include <string>
int myfunction(const char *filename) {
String S(filename);
return 0;
}
C file cmain.c
C 文件 cmain.c
#include "cppfile.hpp"
int main(int argc, char **argv)
{
int i = myfunction(argv[1]);
printf("%d\n", i);
return 0;
}
Compiling:
编译:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
采纳答案by Miles Rout
You want something more like this (and here I will use a slightly more meaningful example):
你想要更像这样的东西(在这里我将使用一个更有意义的例子):
C/C++ header - animal.h
C/C++ 头文件——animal.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 implementation file - animal.cpp
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 client code - main.c
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: %d\nHeight: %f", animal_getage(a), animal_getheight(a));
animal_destroy(a);
return 0;
}
C++ client code - main.cpp
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;
}
So when you compile the library, you compile animal.cpp
with a C++ compiler. You can then link to it with C code, and use the animal_xxx
functions.
因此,当您编译库时,您animal.cpp
使用 C++ 编译器进行编译。然后,您可以使用 C 代码链接到它,并使用这些animal_xxx
函数。
Note the use of struct animal
and Animal
. Animal
is a normal C++ type. It's exactly what it looks like. struct animal
, on the other hand, is an "opaque" type. That means that your C program can see it's there, and can have one, but it doesn't know what is inside it. All it knows is that it has a function that takes a struct animal*
.
使用注意事项struct animal
和Animal
。Animal
是一个普通的 C++ 类型。这正是它的样子。struct animal
另一方面,是“不透明”类型。这意味着您的 C 程序可以看到它在那里,并且可以拥有一个,但它不知道里面有什么。它只知道它有一个函数,它接受一个struct animal*
.
In a real library you will want to have customisation points for memory allocation. So assuming this is the library libjungle
, you probably want at least jungle_setmalloc
and jungle_setfree
with sensible defaults. You can then set up the global new
and delete
in libjungle
's C++ code to use these user-defined functions.
在真正的库中,您将希望拥有用于内存分配的自定义点。因此,假设这是 library libjungle
,您可能至少需要jungle_setmalloc
并jungle_setfree
具有合理的默认值。然后,您可以设置 globalnew
和delete
inlibjungle
的 C++ 代码以使用这些用户定义的函数。
回答by c.fogelklou
This is entirely possible. Here is how, quickly: 1.) You have a header.h with a C API that doesn't include any Cplusiness.
这是完全有可能的。方法如下: 1.) 您有一个 header.h,其中包含一个不包含任何 Cplusiness 的 C API。
#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
Then in the .cpp, you simply create some C-API functions that can even include CPP right in them:
然后在 .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.
In your case, you don't actually need any CPP code declared in your header since you are calling external libraries. But you need to create C-compatible functions in your CPP file which can call out to CPP libraries. Use extern "C" for those functions that need to be called from C files, and then use C-structs instead of classes and, if classes are needed, use void * to point to them and then cast them back to their class from the C function any time you need to access them. A standard makefile should be able to compile this just fine, assuming it compiles .cpp files as .cpp and understands extern "C" {}
在您的情况下,您实际上不需要在标头中声明任何 CPP 代码,因为您正在调用外部库。但是你需要在你的 CPP 文件中创建 C 兼容的函数,它可以调用 CPP 库。对那些需要从 C 文件调用的函数使用 extern "C",然后使用 C 结构而不是类,如果需要类,请使用 void * 指向它们,然后将它们从C 函数在您需要访问它们的任何时候。一个标准的 makefile 应该能够很好地编译它,假设它将 .cpp 文件编译为 .cpp 并理解 extern "C" {}
回答by Jonathan Leffler
Your C code cannot use the C++ header <string>
. You have to ensure that the functions in the C++ API that are to be called from C are declared extern "C"
(as you have), and use only types recognized by a C compiler (as you have).
您的 C 代码不能使用 C++ 标头<string>
。您必须确保要从 C 调用的 C++ API 中的函数已声明extern "C"
(如您所见),并且仅使用 C 编译器识别的类型(如您所见)。
You also need to link with the C++ compiler if any of your code is in C++. You can do it otherwise if you're prepared to spend a lot of energy getting the loader options right, but it is far simpler just to use the C++ compiler:
如果您的任何代码使用 C++,您还需要与 C++ 编译器链接。如果您准备花费大量精力使加载程序选项正确,您可以这样做,但仅使用 C++ 编译器要简单得多:
gcc -c cmain.c
g++ -fPIC -shared -o cppfile.so cppfile.cpp
g++ -o cmain cmain.o cppfile.so
Of course, you need to:
当然,你需要:
- Add
#include <stdio.h>
incmain.c
. - Use
std::string S(filename);
incppfile.cpp
.
- 添加
#include <stdio.h>
在cmain.c
。 - 使用
std::string S(filename);
在cppfile.cpp
。
Also, if the program is invoked without arguments, you get:
此外,如果在没有参数的情况下调用程序,您将得到:
$ ./cmain
terminate called throwing an exceptionAbort trap: 6
$ ./cmain x3
0
$
You need to protect against misuse, even in test programs.
您需要防止误用,即使在测试程序中也是如此。