[英]Co-mingling low-level C/C++ code
I am planning to write a code library to access some hardware at a low-level (ie flipping register bits and such). 我打算编写一个代码库来访问低级别的硬件(即翻转寄存器位等)。
Previously, I wrote everything as C functions and used extern "C" to make the library compile for both C and C++ code. 以前,我将所有内容都写成C函数,并使用extern“C”来编译C和C ++代码的库。 So, both C and C++ users merely had to include the header file and call the functions as they were.
因此,C和C ++用户只需要包含头文件并按原样调用函数。
Now, I am thinking of organising things as classes. 现在,我正在考虑将事物组织成课程。 For example, I can put all the functions to initialise, configure, transmit and receive a UART in a class.
例如,我可以将所有功能放在一个类中初始化,配置,发送和接收UART。 This works fine in C++ but how about C?
这在C ++中运行良好,但C怎么样? I can't extern "C" an entire class.
我不能把“C”作为整个班级。
One thing that I was thinking of: write everything in standard C functions escaped with extern "C". 我想到的一件事是:用extern“C”转义标准C函数中的所有东西。 Then, provide a wrapper class for C++, that has a bunch of inline methods that call these 'C' functions.
然后,为C ++提供一个包装类,它有一堆调用这些'C'函数的内联方法。
int foo_bar (int *address, int data) {...} // extern C stuff
int foo::bar (int *address, int data) { return foo_bar(address, data); } // inline method
Is that okay? 这样可以吗? Any other ideas?
还有其他想法吗? Best practices?
最佳做法?
There is some precedent for what you're proposing - Microsoft's MFC classes are just C++ wrappers around the C-compatible Windows API. 你提出的建议有一些先例 - 微软的MFC类只是围绕C兼容的Windows API的C ++包装器。
Before you start though, you should have some goal in mind beyond just creating busywork for yourself. 在开始之前,除了为自己创建繁忙工作之外,您应该考虑一些目标。 The C++ should be easier to work with than the C, or you're not gaining anything.
C ++应该比C更容易使用,或者你没有获得任何东西。
One solid reason for doing this is if your C interface uses the typical "handle" idiom to represent resources. 这样做的一个坚实原因是,如果您的C接口使用典型的“句柄”惯用语来表示资源。
OpaqueThingHandle t = CreateOpaqueThing();
DoStuffWithOpaqueThing(t);
DestroyOpaqueThing(t);
In C, to achieve information hiding, the OpaqueThingHandle
is often a typedef for void *
so that clients have no visibility of how it is implemented. 在C中,为了实现信息隐藏,
OpaqueThingHandle
通常是void *
的typedef,因此客户端无法看到它的实现方式。
C++ wrappers will be able to add something genuinely useful simply by applying RAAI - mapping construction and destruction on to the functions that aquire or free the resource identified by the handle type: 只需将RAAI映射构造和破坏应用于获取或释放句柄类型标识的资源的函数,C ++包装器就能够添加真正有用的东西:
class OpaqueThing : boost::noncopyable
{
OpaqueThingHandle handle;
public:
OpaqueThing()
: handle(CreateOpaqueThing()) {}
~OpaqueThing()
{ DestroyOpaqueThing(handle); }
void DoStuff()
{ DoStuffWithOpaqueThing(handle); }
};
You can do that, but what does it gain you? 你可以做到这一点,但它能带给你什么? Unless the class adds some functionality, I would stick with the free function approach.
除非该类增加了一些功能,否则我会坚持使用自由函数方法。
On the other hand, it is possible for the class approach to make the C functions much easier to use, by doing things like managing buffers etc. for the classes clients - the class still uses the C API to do the actual work. 另一方面,通过为类客户端管理缓冲区等操作,类方法可以使C函数更容易使用 - 类仍然使用C API来完成实际工作。
You'd need to export both the C - method-based and the C++ - class interface. 您需要导出基于C方法和C ++类的接口。 You can go both ways - either a thin C++ wrapper around the C functions, or C functions around the C++ instance.
您可以采用两种方式 - 围绕C函数的简化C ++包装,或围绕C ++实例的C函数。
For the latter, a typical pattern is this: 对于后者,典型的模式是这样的:
void * c_open_thing(id) { return new CThing(id); }
void c_close_thing(void * handle) { delete (CThing) handle; }
int c_transmit(void * handle, transmitbuf)
{ return ((CThing *)handle)->Transmit(transmitbuf); }
Such a simplistic wrapper is pointless, no matzter in which way you do it, though. 这样一个简单的包装器是没有意义的,但是你可以通过哪种方式实现它。 The C++ wrapper could add value in the following ways:
C ++包装器可以通过以下方式增加价值:
Enforce construction / destruction requirements 执行施工/销毁要求
Using cosntructor/destructor is usually not sufficient here, unless you can provide assignment and copy construction. 除非您可以提供赋值和复制构造,否则在这里使用cosntructor /析构函数通常是不够的。 I'd typically use a reference counted handle .
我通常使用引用计数句柄 。
Error handling 错误处理
This might be required cleanup, converting errors to (meaningful!) exceptions etc. 这可能需要清理,将错误转换为(有意义的!)异常等。
Thread safety Of course, if you control the original library, you can add it there. 线程安全当然,如果你控制原始库,你可以在那里添加它。
... ...
I understand that you want to benefit from the abstraction capabilities of C++ but still have your code accessible to code written in C. One approach to achieve this is to write the bulk of your code in C++ and then create a set of thin extern "C" wrapper functions that will interface your code to the C world. 我知道您希望从C ++的抽象功能中受益,但仍然可以使用C编写的代码访问您的代码。实现此目的的一种方法是用C ++编写大量代码,然后创建一组精简的外部“C” “将代码与C世界连接起来的包装函数。
The approach you suggest also works, but, as another respondent noted, it doesn't buy you any additional power. 你建议的方法也有效,但是,正如另一位受访者指出的那样,它不会给你任何额外的力量。
Note that both approaches introduce a slight performance penalty over the plain C function approach. 请注意,与普通C函数方法相比,这两种方法都会引入轻微的性能损失。 In your proposal the C++ code pays the price, in mine the C code pays the price.
在您的提案中,C ++代码支付了价格,在我的C代码支付价格。 This can be minimized by defining the functions as inline.
可以通过将函数定义为内联来最小化这一点。
Frankly, I don't see what having essentially duplicate C and C++ functions buys you. 坦率地说,我没有看到基本上重复的C和C ++函数会给你带来什么。
I'd suggest keeping the C functions as basic as possible, defining an API with all the primitives exposed and nothing fancy. 我建议尽可能保持C函数的基本功能,定义一个API,其中所有基元都暴露出来并且没什么特别的。 Then define the C++ classes at a much higher level, so a UART would have a constructor, destructor, meaningful methods, that sort of thing.
然后在更高级别定义C ++类,因此UART将具有构造函数,析构函数,有意义的方法等等。 It would have all necessary data storage.
它将拥有所有必要的数据存储。 The C++ classes would not expose all possible primitives;
C ++类不会暴露所有可能的原语; in order to do something different, you'd write a new member function or class or whatever, calling the C API.
为了做一些不同的事情,你要编写一个新的成员函数或类或其他什么,调用C API。
That's the approach in systems like OCCI (the Oracle C++ Call Interface) and MFC and others, and it works well. 这是OCCI(Oracle C ++调用接口)和MFC等系统中的方法,它运行良好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.