How do I write good C ++ when interacting with low-level (er) interfaces?

In my C ++ code, I have to deal with interfaces written in C as well as CUDA cores. I wrote some questions here on Stackoverflow how to do this or that in C ++. I have many answers like: "Don't do it like this. There are better solutions in C ++, look at this or that." On the other hand, I think I really had to do it this way due to the C interfaces or CUDA interaction.

In short: I am increasingly realizing that C interfaces and low-level materials lead to difficulties when developing code in good C ++ philosophy.

What do I need now? I'm looking for some literature like Effective C ++, but specifically for people who have to deal with low level aspects.

+3


source to share


1 answer


There are a couple of concepts you want to keep in mind when you are an architect and design your code:

  • Encapsulation / hiding data
  • Propagating changes
  • Details / Abstract
  • Connection / dependencies

General architecture is to use pyramid layout for abstraction. The lowest layer knows the specifics of the hardware. Each layer up is an abstraction from the hardware to the application.

Encapsulation and hiding data

The idea here is that every thing associated with one piece of hardware should be in encapsulation. Regular devices that use the same functionality, except that they are located at different addresses, must inherit from the same interface.

For example, given 3 USB ports at addresses 0x1000, 0x2000 and 0x3000, they will all be the same. The only difference is that their hardware registers have different addresses. So there should be USB_Interface_Base_Class and either 3 instances or 3 child classes.

The USB class should only expose fundamental functionality. The user of the classes doesn't care about the hardware registers, only about the I / O execution. This way the details are hidden from outside users of the class.

Propagating changes

During research and development, hardware is unstable and subject to change. It can also change during production. The goal is to reduce the spread of change. For example, if the USB interface was changed to Wireless, the hardware access level should change, but the change should not propagate deep into the application. The fewer modules to change, the better.



Details and abstraction

Each layer of hardware should be at a higher level of abstraction than the previous, lower layer.

For example, the highest abstraction is: `cout <<" Hello \ n "; The next layer down can buffer the data and call the "driver".
The driver says he wants to talk to the character output device. The default character device is connected to USB.
The USB driver talks to the hardware interface to set up registers and transfer data.

At the highest level, the user wants to output text to the default output port, which is an abstraction. The layers below fill in the details to complete the task.

Connection / dependencies

A dependency between two or modules is a relationship. There is a certain degree of tension adhesion. Two modules are considered tightly coupled when an internal change to one module requires a change to another. Two modules are loosely coupled when an internal change in one module does not affect the other.

The purpose of a loose coupling is to help reduce the propagation of changes throughout the system. If one module accesses another's data members, and the data members change, the calling module must change. If the calling module uses an interface, the provider can change its data members without affecting the calling module in any way. The propagation of the changes has stopped.

Summary

There's more access to hardware than coding. The principles of encapsulation, change propagation, abstraction, and linking should be considered first. The hardware access code must follow the principles. A good process is to architect and design with principles in mind before coding.

0


source







All Articles