简体   繁体   English

混合低级C / C ++代码

[英]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.

相关问题 C ++低级文件加密功能 - C++ low-level file encryption function C++ 中“低级”多线程的基本示例是什么? - What is a basic example of "low-level" multi-threading in C++? 如何在Windows上使用C ++访问低级硬件I / O功能? - How can I access a low-level hardware I/O functions in C++ on Windows? 带有Objective C类的Mingling C ++类 - Mingling C++ classes with Objective C classes 除非在XP兼容模式下运行,否则Windows Vista / 7上的低级C ++应用程序崩溃 - Low-Level C++ App Crashes on Windows Vista/7 Unless Run in XP Compatibility Mode 将对象复制到另一个对象时,为什么 C++ 需要对两个对象进行低级 const 限定? - Why does C++ require low-level const qualification on both objects when copying an object to another? C++ 中“低级”容器数据的原始指针、智能指针或 std::vector - Raw pointer, smart pointer or std::vector for “low-level” container data in C++ Python 在反序列化 json 方面比 C++ 快。 为什么? Python 3 中的 json 库是用 C/C++ 还是其他低级语言编写的? - Python faster than C++ in deserializing json. Why? Is the json library in Python 3 written in C/C++ or other low-level language? C优化 - 低级代码 - C optimization - low level code C++ 有助于理解低级代码的语法 - C++ help to understand syntax of low level code
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM