如何调用C++;方法从C? 我有一个C++类,我用一些C文件编译它。 我想调用C++中定义的函数,实际上是C++类,我该怎么办?

如何调用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

以下声明显示了我的意思:可能存在语法错误:

串行通信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 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约定。(由于您的功能没有 返回值,这可以通过返回代码轻松处理。)


  • 解决这个问题的常用方法是提供一个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.c
    cc-cmain.c
    但随后将二进制文件链接为