【发布时间】:2017-12-27 04:32:59
【问题描述】:
我的任务是为我们的硬件传感器构建一个跨平台 API,以使它们对 3rd 方开发人员更有用。目前,我们有很多遗留应用程序,其中硬件层构建在 GUI 中及其周围。
我想做的是移除硬件层并实现一个可靠但设计良好的跨平台 API,然后可以将其提供给第三方开发人员,以帮助将我们的硬件集成到他们的平台中。
我意识到,在 Stack Overflow 术语中,这可能是一个危险信号,但我还是会问这个问题。
我们现有的代码库是多语言(C#、C++/Qt、Delphi 等),但只能在 Windows 上运行。我想进一步推进这一点,并至少将 Linux 纳入其中,并可能进一步支持一些 Mac/OSX。
纵观全局,我对未来任务的理解是在 API 方面创建一个“黑盒”。诸如connect 之类的函数将接受几个参数并传递某种设备handle,而底层连接代码对用户隐藏。然后可以将此句柄传递给各种 control 函数,以使设备执行特定功能 - callbacks 可用于异步通知。
现在这让我想到了我的问题:
对于connect、read或write等需要操作系统底层IO子系统知识的函数,这部分代码库是否可以用C++编写为一个类而不是比平 C?
因此,请考虑以下伪代码作为粗略的device:
class Device : abstract {
bool connect(...) abstract
}
#ifdef _WIN32
class WindowsDevice : public Device {
// Calls Windows-specific functions
bool connect(...)
}
#elif __linux
class LinuxDevice : public Device {
// Calls Linux-specific functions
bool connect(...)
}
#else
#error Bad platform
#endif
然后是 API 函数...
Device *inst;
bool DEVICE_Connect(...) {
// bind the device instance here
#ifdef _WIN32
inst = new WindowsDevice();
#else
inst = new LinuxDevice();
#endif
}
bool DEVICE_Command(uint8_t cmd) {
if (!inst)
FAIL;
inst->SendCommand(cmd);
}
或者,实现应该是更C 风格的API,例如以下伪代码:
#ifdef _WIN32
HANDLE *inst;
#elif __linux
void *inst;
#else
#error Bad platform
#endif
bool DEVICE_Connect(void *handle) {
#ifdef _WIN32
// Windows connect-to-whatever function
#elif __linux
// Linux connect-to-whatever function
#else
return FALSE;
#endif
}
bool DEVICE_Command(uint8_t cmd) {
if (!inst)
FAIL;
#ifdef _WIN32
// Windows write command
#elif __linux
// Linux write command
#else
return FALSE;
#endif
}
基本上,我希望得到一些good-practice 以前遇到过这种情况的人的建议。将 C++ 用于实现代码但随后为最终用户公开其周围的 C 包装器是否有任何优点?这一切都应该在平面 C 中完成吗?
最后一个问题:
有问题的硬件设备有各种连接选项,从 TCP 和 UDP 套接字到 USB HID,然后是简单的旧 RS232,因此我需要调用的底层功能将非常多样化。
考虑到这一点,使用最低级别的函数调用是否有任何实际意义(或好处) - 我的意思是,旨在使用 fopen 打开文件,而不是CreateFile 在 Windows 中?从跨平台的角度来看,这是否对我有帮助,或者这只是一种愚蠢的方式,限制了我在重叠 io 等方面的选择?我可能已经回答了我自己的问题...
感谢任何可以提供任何建议、指南或最佳做法的人。
【问题讨论】:
-
我不明白你为什么要继承
Device。使用条件编译,无论如何您将只有特定于平台的实现,而调用者并不关心它是在 Windows 中还是在 linux 中。在处理硬件的时候,我个人的感觉是:只用C,可选地提供C++ wrappers。但这实际上取决于您在实施中究竟需要做什么。 -
感谢您的评论。最终,这就是重点——调用者不需要关心,他们所拥有的只是一个头文件和相应的库文件。他们永远不需要担心幕后发生的事情。您对
inherited方法的看法是正确的,但从我的角度来看,它感觉更易于维护——但也许情况并非如此。我更倾向于 C 而不是 C++ -
A C API 可能更容易从其他语言中使用。不过,您是使用 C 包装器在 C++ 中实现它还是以其他方式实现它取决于您。
-
我同意@melak47,C API 是要走的路。除非您要为 API 提供源代码并让用户为他们的目标操作系统重新编译它,否则即使在同一个操作系统上编译器之间的差异(命名约定 ABI 等)也会让生活变得困难。