如何调用C++;方法从C? 我有一个C++类,我用一些C文件编译它。 我想调用C++中定义的函数,实际上是C++类,我该怎么办?
以下声明显示了我的意思:可能存在语法错误: 串行通信cpp如何调用C++;方法从C? 我有一个C++类,我用一些C文件编译它。 我想调用C++中定义的函数,实际上是C++类,我该怎么办?,c++,c,class,extern,C++,C,Class,Extern,以下声明显示了我的意思:可能存在语法错误: 串行通信cpp class MyClass { void sendCommandToSerialDevice(int Command, int Parameters, int DeviceId) { //some codes that write to serial port. } } 外部 int main(int argc, char ** argv) { //what am I going to wri
class MyClass {
void sendCommandToSerialDevice(int Command, int Parameters, int DeviceId) {
//some codes that write to serial port.
}
}
外部
int main(int argc, char ** argv) {
//what am I going to write here?
}
#include "serial_comm_wrapper.h"
int main(int argc, char ** argv) {
MyClass *instance = MyClass_new();
MyClass_sendCommandToSerialDevice(instance, ...);
}
如果你想把它做对 串行通信包装器.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
串行通信包装器.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);
}
外部
int main(int argc, char ** argv) {
//what am I going to write here?
}
#include "serial_comm_wrapper.h"
int main(int argc, char ** argv) {
MyClass *instance = MyClass_new();
MyClass_sendCommandToSerialDevice(instance, ...);
}
您必须传递一个附加参数,该参数的地址为 要在其上调用函数的对象。比如:
extern "C" void SendCommandToSerialDevice( void* object,
int command, int parameters, int deviceId )
{
static_cast<MyClass*>( object)->sendCommandToSerialDevice(
command, parameters, deviceId );
}
extern“C”void SendCommandToSerialDevice(void*对象,
int命令、int参数、int设备ID)
{
静态强制转换(对象)->sendCommandToSerialDevice(
命令、参数、设备ID);
}
main
当然必须找到类的实例
不知怎么的
编辑:
关于其他答复中提出的一些问题:
main
编译为C。这是未定义的
行为,实际上可能意味着您的构造函数将
不能在静态对象上调用。(如果代码位于DLL中,
你很好。标准没有说任何关于DLL的内容,但是
实际上,它们是有效的。)解决这个问题的常用方法是提供一个C包装器API。编写一个C函数,该函数使用指向
MyClass
对象的指针(因为MyClass
不是有效的C,您需要提供一些名字,最简单的是移动void*
和其他参数。然后在C++内部执行函数调用:
extern "C" void* MyClass_create() {
return new MyClass;
}
extern "C" void MyClass_release(void* myclass) {
delete static_cast<MyClass*>(myclass);
}
extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) {
static_cast<MyClass*>(myclass)->sendCommandToSerialDevice(cmd,params,id);
}
不能从C.</P>调用C++代码
您需要生成一个C++接口,可以从C.< /P>调用 像这样的
// 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;
}
请注意,不能让“异常”通过墙进入C代码,因为这是明确的未定义行为 > P> 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文件)
main.c
int main(int argc, char ** argv) {
MyClass *c = new_MyClass();
MyClass_sendCommandToSerialDevice(c, 1, 0, 123);
}
当然,由于C和C++代码之间的资源和错误处理可能不同,所以你必须解决如何处理你的组合。例如,上面的代码只是泄漏了一个
MyClass
对象,而不是清理,并且对异常没有任何作用。您不能将external.c
重命名为external.cpp
并调用类的函数吗?有很多这样的c文件。无法重命名。那么,MyClass::sendCommandToSerialDevice()如何代码>?@H2CO3:这不是一个静态函数,所以不能用那种方式调用它。但是我想我明白你的意思了。@EnesUnal:如果这个函数不是静态的,那么你需要一个对象来调用它。不需要是新对象,但必须存在某些对象。否则,请将函数标记为静态
。您不能在void*
上使用dynamic\u cast
。另外一个问题是,main
如何将其poonter获取到对象。您不能从void*
@JamesKanze中执行dynamic\u cast
:好的,我更正了它。现在使用C样式类型转换(我不知道是静态转换还是重新解释转换更合适)。@datenwolf我使用static\u转换
,但是当从void*
进行转换时,两者都保证具有相同的语义。@JamesKanze:你没有注意到我的typedef吗?至于在C端会发生什么:指向结构的C不透明指针的行为与void*
没有区别,因此这与在没有显式强制转换的情况下编写void*
完全相同。此外,C标准还断言,将void*
强制转换为限定类型指针不会改变指针的值。所以基本上这只是语义糖。但是非常好的糖。在C端,编译器只看到一些指针(其中有一个C++代码创建的值),这个值不被触摸,不能解引用。但在C++方面,指针具有实际意义。关于异常,这是一个好的事情,但一般来说,你可以指望它们通过C。另一方面,他的例子编译了主< <代码> >,这意味着对静态对象的构造函数不被调用。@詹姆斯坎泽:请看我的评论和你的回答。执行静态初始化的不是包含main的编译单元,而是最终也将调用main的运行库。如果程序与C++运行时链接,你就可以了。您可以在C编译单元中很好地实现main。这是有保证的,还是“大多数编译器都是这样做的”@datenwolf您的评论是错误的。您只需描述一个特定的实现是如何实现的。大多数现代的实现可能会做类似的事情,因为他们希望在DLL中支持C++,并且需要技术,但是我使用了没有实现的实现。@ JAMESKANZE:我知道没有实现,其中main函数是进程入口点(除非您明确地告诉链接器这样做)。即使是我所知道的所有嵌入式系统编译器,main也是通过运行时系统调用的。我知道至少以下实现是这样工作的。MSVC++,GNU C++,DMC++,Borland C++,英特尔编译器套件和开放WATCOM。关于关注1)技术上,静态初始化不是主要的,而是运行初始化后最终调用main的运行环境。只要你把你的可执行文件链接到C++运行时,你就可以了。例如,您可以使用c编译器编译main.ccc-cmain.c
但随后将二进制文件链接为