从外部设备读出的帧存储在共享内存中(在结构中),供主(C ++)应用程序和ANSI C库使用。
由于原因有点过于宽泛而无法在此解释,库必须保持纯ANSI C,并且必须保持对其“纯ANSI C”形式的结构的访问。但主要的应用程序在很多地方使用数据,以“ANSI C”方式执行此操作是一件麻烦事,将其视为一个愚蠢的数据容器。如果它是一个类会更好 - 如果我可以添加构造函数,复制构造函数,比较运算符,neater'是有效的'方法(当前检查为在其中一个struct字段中没有幻数),通常很多C ++类可以做的事情,但ANSI C结构不能。除非我用共享内存中的类替换struct,否则会破坏与库的兼容性。
实现这一目标的巧妙方法是什么?创建一个继承自struct的类?通过构图继承?一个单独的类,有一组转换方法?还有什么别的我没想过的?一些透明的方法可以保持数据对C不变,但是增强了C ++的类功能?
注意:C ++和C都在结构的相同实例上运行。主app从设备中读出帧,写入共享内存中的结构,然后调用库函数在帧上做他们的魔术(可能,但不一定修改它;业务逻辑),然后对它执行自己的操作(显示,记录,在其他媒体上重播等。
我可以完全控制C ++代码,但C代码主要是不受控制;我可以创建一个结构的本地副本,如果这是有益的,但我的副本和'业务逻辑实例'应该保持同步,或者至少在每个库函数调用之前和之后同步(在我的控制下操作,但是时间决定按系统要求。)
编辑: 根据要求提供一些额外的细节:
“业务逻辑”在C库中实现,由用户输入的外部应用程序(用于PC)生成的自定义C代码(用于绘制逻辑的图形界面;认为“框图”),各不相同每台设备(许多用户,甚至更多设备)。该设备需要交叉编译;只有ANSI C交叉编译器才能以易于与PC应用程序捆绑在一起的形式提供; C ++交叉编译器仅在系统开发人员(我的)PC上可用;它的安装过程和许可证使得无法捆绑(已售出)的发电机应用程序。
设备上的库和C ++应用程序使用共享内存作为所有输入和输出数据的存储,原因有两个:
答案 0 :(得分:2)
创建一个派生自C-struct的类,但要确保内存布局保持不变,即不使用虚方法(这些将添加vtable)或添加成员变量。在C ++ 11术语中,这将被称为标准布局类。有关详细信息,请参阅此处:
What are Aggregates and PODs and how/why are they special?
遵守此规则,您可以安全地在C struct和C ++类之间进行转换,并使用适当的成员函数。
注意:关于分配数据结构,您需要使用与分配相同的一组函数,即如果已使用malloc()分配,则必须使用free()释放它,如果已分配使用new时必须使用delete发布。因此,如果要从C和C ++代码中分配对象,则限制为malloc / free,因为C中没有新的/ delete。
答案 1 :(得分:1)
如果你以某种方式将其子类化,那么基础结构将需要一个vtable。您可以更改结构以包含这些元素,然后将其转换为/从类/结构中。您需要使用reinterpret_cast<>()。
然而,这是一个糟糕的主意。请不要这样做。
相反,在包含结构的类中实现业务逻辑。这样您就不需要支持在两个代码库之间编组结构,您可以保留结构的一个副本。
但是请记住将结构标记为volatile,如果它需要被C ++代码不知道的任何形式的后台线程更改。
答案 2 :(得分:0)
简单,将你的c结构移动到c ++ PIMPL
// A.h
class A
{
//...
private:
struct impl;
static std::unique_ptr<impl> p_impl;
}
// A.cpp
std::unique_ptr<A::impl> A::p_impl;
struct A::impl
{
// c code here
}
答案 3 :(得分:0)
我的理解是C ++管理代码分配一块共享内存,而C和C ++代码协调将在哪里写入哪种类型的信息。 C ++管理器定期检查内存中的位置,知道它希望找到什么类型的数据。我想那时C ++代码有一个void*
指向your_c_struct*
指针的表来检查。在前一种情况下,可以通过reinterpret_cast<your_c_struct*>(void_ptr)
随时转换这些内容。因此,我假设C ++代码有一个指向共享内存中C结构的指针表。在这种情况下,我认为解决方案是创建一个伪RAII类,它可以指向共享内存或拥有的非拥有位置,并在堆上分配/解除分配内存。这看起来像是:
class Wrapper {
public:
Wrapper() : owned(true), data(new your_c_struct{}) {}
Wrapper(your_c_struct* _data) : owned(false), data(_data) {}
~Wrapper() {
if (owned)
delete data;
}
// copy constructors
// overloaded comparison operators
private:
bool owned;
your_c_struct* data;
};
构造此类有两种主要方法:在堆上创建新对象或向其传递指向它不拥有的共享内存的指针。我已经成功地将这种技术用于GSL库,其中共享内存中的C结构的等价物是由GSL数值算法分配并返回的C结构。我进一步提出了第二个构造函数,并提供了一个命名构造函数Wrapper Wrapper::SoftWrap(your_c_struct* _data)
。