如何从C调用C ++方法?

我有一个C ++类,我正在用一些C文件编译它。

我想调用一个用C ++定义的函数,实际上是在C ++类中,所以我该怎么做?

以下声明显示我在说什么:可能存在语法错误:

serial_comm.cpp

class MyClass { void sendCommandToSerialDevice(int Command, int Parameters, int DeviceId) { //some codes that write to serial port. } } 

external.c

 int main(int argc, char ** argv) { //what am I going to write here? } 

解决此问题的常见方法是提供C包装器API。 编写一个带有指向MyClass对象的指针的C函数(因为MyClass不是有效的C,你需要提供一些名字,最简单的就是移动void* )和其余的参数。 然后在C ++里面执行函数调用:

 extern "C" void* MyClass_create() { return new MyClass; } extern "C" void MyClass_release(void* myclass) { delete static_cast(myclass); } extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) { static_cast(myclass)->sendCommandToSerialDevice(cmd,params,id); } 

然后C代码使用C api创建对象,调用函数并释放对象:

 // C void* myclass = MyClass_create(); MyClass_sendCommandToSerialDevice(myclass,1,2,3); MyClass_release(myclass); 

您必须传递一个额外的参数,并使用该对象的地址来调用该函数。 就像是:

 extern "C" void SendCommandToSerialDevice( void* object, int command, int parameters, int deviceId ) { static_cast( object)->sendCommandToSerialDevice( command, parameters, deviceId ); } 

当然, main意志必须以某种方式找到该类的实例。

编辑:

关于在其他答案中提出的一些观点:

  1. 在您的示例中,您将main编译为C.这是未定义的行为,实际上可能意味着您的构造函数不会在静态对象上调用。 (如果你的代码在DLL中,你就可以了。标准没有说明DLL的任何内容,但在实践中,它们可以工作。)

  2. 如果您通过exception报告错误,那么您将不得不更改签名以其他方式报告它们,并包装代码以捕获所有exception,并将它们转换为C约定。 (由于您的函数没有返回值,因此可以通过返回代码轻松处理。)

如果你想做正确的话

serial_comm_wrapper.h

 #ifdef __cpluscplus class MyClass; extern "C" { #else struct MyClass; typedef struct MyClass MyClass; #endif MyClass *MyClass_new(); void MyClass_sendCommandToSerialDevice(MyClass *instance, int Command, int Parameters, int DeviceId); #ifdef __cpluscplus } #endif 

serial_comm_wrapper.cc

 #include "serial_comm_wrapper.h" #include "serial_comm.hh" MyClass *MyClass_new() { return new MyClass(); } void MyClass_sendCommandToSerialDevice(MyClass *instance, int Command, int Parameters, int DeviceId) { instance->sendCommandToSerialDevice(command, Parameters, DeviceID); } 

external.c

 #include "serial_comm_wrapper.h" int main(int argc, char ** argv) { MyClass *instance = MyClass_new(); MyClass_sendCommandToSerialDevice(instance, ...); } 

你不能只是从C调用C ++代码。

您将需要生成可以从C调用的C ++接口。

像这样的东西

  // interface.h #ifdef __cplusplus extern "C" { #endif void createMyclass(); void callMyclassSendCommandToSerialDevice(int Command, int Parameters, int DeviceId); void destroyMyclass(); #ifdef __cplusplus extern } #endif 

然后你这样做:

  static MyClass *myclass; void createMyclass() { try { myclass = new MyClass; } catch(...) { fprintf(stderr, "Uhoh, caught an exception, exiting...\n"); exit(1); } } void callMyclassSendCommandToSerialDevice(int Command, int Parameters, int DeviceId) { // May need try/catch here. myclass->sendCommandToSerialDevice(Command, Parameters, DeviceId); } void destroyMyclass() { delete myclass; } 

请注意,您不要让“exception”通过墙到C代码,因为这是明确的未定义行为。

您不能直接在C中调用C ++方法。相反,您可以创建一个C包装器,然后调用它:

C / C ++兼容头文件:

 #ifdef __cplusplus extern "C" { #endif struct MyClass; MyClass *new_MyClass(); void MyClass_sendCommandToSerialDevice(MyClass *c, int Command, int Parameters, int DeviceID); #ifdef __cplusplus } // extern "C" #endif 

实现(.cpp文件)

 #include "my_c_compatiblity_header.h" #include "MyClass.h" extern "C" MyClass *new_MyClass() { return new MyClass(); } extern "C" void MyClass_sendCommandToSerialDevice(MyClass *c, int Command, int Parameters, int DeviceID) { c->sendCommandToSerialDevice(Command, Parameters, DeviceID); } 

main.c中

 int main(int argc, char ** argv) { MyClass *c = new_MyClass(); MyClass_sendCommandToSerialDevice(c, 1, 0, 123); } 

当然,由于C和C ++代码之间的资源和error handling可能不同,因此您必须确定如何在您的情况下处理组合。 例如,上面只是泄漏了一个MyClass对象而不是清理,并且没有对exception做任何事情。