将C++类放入C结构中,以便在C++函数(C/C++混合代码)中使用



注意:这与C/C++链接或extern关键字无关。请仔细阅读,然后再将我的问题与看似相似的问题联系起来,谢谢!

我认为这是一个有点不寻常的问题,因为我在浏览网页时没有发现任何关于这个的信息。

我正在编程一个嵌入式系统。主模块是用C编写的,而子模块是用C++编写的。举例说明:

submodule.hpp
/            
/              
main.c        submodule.cpp

现在,我想保留C++子模块使用的数据,并将其包含在主脚本的静态变量中,这样我就可以从main调用子模块函数,并在每次调用时提供上下文数据。但是该数据还必须包含一个子模块函数所使用的类,但C当然不知道如何处理类。因此,我不得不在没有主.C-script注意到的情况下(给我一个错误(,偷偷地把一个类放入我的C结构中。我怎样才能做到这一点?

我认为这样的东西可以工作:

struct data_for_cpp_submodule {
int a;
int b;
void *class;
}

然后铸造空指针";类";回到合适的类,这样我就可以在C++脚本中使用它了。这能奏效吗?还是我完全错了?

请注意,OP强调:

主模块用C编写,而子模块用C++编写。

IMHO,为C++submodule添加C绑定是完全可以的,这样它就可以在C代码中使用。

OP的例子(增强了一点,使其成为MCVE(:

submodule的C++代码

标题submodule.hpp:

#ifndef SUB_MODULE_HPP
#define SUB_MODULE_HPP
class Test {
private:
int a = 0;
int b = 0;

public:
Test() = default; // default constructor
Test(int a, int b): a(a), b(b) { } // value constructor
Test(Test&) = delete; // say: copy constructor disabled
Test& operator=(Test&) = delete; // say: copy assignment disabled

public:
int exec() const;
};
#endif // SUB_MODULE_HPP

来源submodule.cpp:

#include "submodule.hpp"
int Test::exec() const { return a + b + 42; }

submodule的C绑定:

标题:submodule.h

#ifndef SUB_MODULE_H
#define SUB_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
struct TestC_;
typedef struct TestC_ TestC; // opaque structure
extern TestC* testNew();
extern TestC* testNewValues(int a, int b);
extern void testDelete(TestC *pTest);
extern int testExec(TestC *pTest);
#ifdef __cplusplus
}
#endif
#endif // SUB_MODULE_H

来源submoduleC.cpp:

#include "submodule.h"
#include "submodule.hpp"
TestC* testNew() { return (TestC*)new Test(); }
TestC* testNewValues(int a, int b) { return (TestC*)new Test(a, b); }
void testDelete(TestC *pTest) { delete (Test*)pTest; }
int testExec(TestC *pTest) { return ((Test*)pTest)->exec(); }

最后但同样重要的是:使用submodule:的示例C程序

#include <stdio.h>
#include "submodule.h"
int main(void)
{
TestC *pTest = testNew();
printf("pTest->exec(): %dn", testExec(pTest));
testDelete(pTest);

pTest = testNewValues(123, -123);
printf("pTest->exec(): %dn", testExec(pTest));
testDelete(pTest);
}

如何编译和链接g++/gcc:

$ ## compile C++ code
$ g++ -std=c++17 -O2 -Wall -pedantic -c submodule.cpp submoduleC.cpp
$ ## compile C code
$ gcc -std=c11 -O2 -Wall -pedantic -lstdc++ main.c submodule.o submoduleC.o
$ ## test
$ ./a.out

输出:

testExec(pTest): 42
testExec(pTest): 42

在coliru上演示

最引人注目的部分可能是opaque structure:

struct TestC_;
typedef struct TestC_ TestC; // opaque structure

(这是我在开始编写自己的C绑定之前从其他C绑定中学到的。(

opaque structure实际上是一个不完整的结构,这可能令人惊讶,但这是故意的。

不透明结构仅在C中用作指针。它不允许取消对任何内容的引用(对于不完整的结构,编译器只是拒绝这样做(。它的唯一目的是";"隧道";通过C代码指向C++CCD_ 13实例的指针。

Test(submoduleC.cpp(的C结合中,必要时将TestC*简单地转换为Test*(反之亦然(。

提示:

我必须链接-lstdc++(标准C++库(。否则,我收到了关于运算符newdelete:的未定义引用的投诉

submoduleC.o: In function `testNew':
submoduleC.cpp:(.text+0xa): undefined reference to `operator new(unsigned long)'
submoduleC.o: In function `testNewValues':
submoduleC.cpp:(.text+0x30): undefined reference to `operator new(unsigned long)'
submoduleC.o: In function `testDelete':
submoduleC.cpp:(.text+0x4b): undefined reference to `operator delete(void*, unsigned long)'
collect2: error: ld returned 1 exit status

其他想法(但可能不那么相关(

我记得

  • 是用C编写的
  • 并提供C++API(也就是C++绑定(

我说的是GTK+和gtkmm(它的C++绑定(。因此,应该提到的是,GTK+实际上是一个OOP库——提供用C实现的面向对象类

两者都是开源项目。因此,每个人都可以看看他们是怎么做的。我曾经看了一眼,印象深刻…

除此之外,我总是建议相反的方法:用C++编写库并添加C绑定,因为这对我来说似乎容易得多

我们总是在Windows中这样做,原因有很多:

  1. 以实现使用不同版本的Visual Studio编译的DLL可以链接在一起。(直到不久,这在C++中几乎是不可能的,但现在,我相信,我读到了微软推出的ABI,这可能会使成为可能。(

  2. 以便为其他语言(例如C#(中的绑定提供基础。

最新更新