Med*_*o42 7 compiler-construction mingw calling-convention binary-compatibility visual-c++
我正在开发一个库,允许其用户(驻留在同一进程中的其他库)交换数据缓冲区和流.该库必须可以从MSVC和mingw代码中使用(更多兼容性不会受到影响,但并非严格必要).为了实现这一点,核心功能应该从一个小的,与编译器兼容的接口提供,以后可以通过使用客户端代码编译的便利层来隐藏.
该库的一个具有挑战性的方面是它必须是可扩展的,以便客户端可以提供自己的缓冲区和流实现,但核心库接口必须在发布后保持稳定.如果您对进一步的背景感兴趣,可以在论坛帖子讨论中阅读.
我试图了解编译器之间二进制兼容性的问题,但由于我是这个主题的新手,我会对我的结果发表评论.我在这里的标准定义的行为(结构可能会失败那个测试),只能在MinGW和MSVC之间的相容性不感兴趣,也许其他的编译器,如果方便可行的.
特别是结构是否兼容?它们统一由函数指针组成,因此我认为填充不会成为问题.另外,这里需要stdcall约定,还是cdecl也能正常工作?我可以不指定它,因为两个编译器都默认为cdecl吗?我是不是该?这就是我现在所拥有的:
#include <stdint.h>
typedef struct {
uint32_t (__stdcall *read)(void*, uint8_t*, uint32_t);
void (__stdcall *write)(void*, const uint8_t*, uint32_t);
uint32_t (__stdcall *getBytesLeft)(void*);
uint8_t (__stdcall *destroy)(void*);
} SharedStreamInterface;
typedef struct {
uint32_t (__stdcall *read)(void*, uint8_t*, uint32_t);
void (__stdcall *write)(void*, const uint8_t*, uint32_t);
uint32_t (__stdcall *getBytesLeft)(void*);
uint8_t (__stdcall *destroy)(void*);
uint32_t (__stdcall *getreadpos)(void*);
uint32_t (__stdcall *getwritepos)(void*);
uint32_t (__stdcall *getlength)(void*);
void (__stdcall *setreadpos)(void*, uint32_t);
void (__stdcall *setwritepos)(void*, uint32_t);
void (__stdcall *setlength)(void*, uint32_t);
} SharedBufferInterface;
extern "C" {
// Functions applicable for both buffers and streams
__stdcall uint32_t readData(uint32_t id, uint8_t* data, uint32_t size);
__stdcall void writeData(uint32_t id, const uint8_t* data, uint32_t size);
__stdcall uint32_t getBytesLeft(uint32_t id);
__stdcall void destroyStreamOrBuffer(uint32_t id);
__stdcall uint8_t streamOrBufferExists(uint32_t id);
// Functions only applicable for buffers
__stdcall uint32_t getReadPos(uint32_t id);
__stdcall uint32_t getWritePos(uint32_t id);
__stdcall uint32_t getLength(uint32_t id);
__stdcall void setReadPos(uint32_t id, uint32_t pos);
__stdcall void setWritePos(uint32_t id, uint32_t pos);
__stdcall void setLength(uint32_t id, uint32_t length);
__stdcall uint8_t bufferExists(uint32_t id);
// Adding new buffers/Streams
__stdcall uint32_t addStream(SharedStreamInterface *interface, void *stream);
__stdcall uint32_t addBuffer(SharedBufferInterface *interface, void *buffer);
}
Run Code Online (Sandbox Code Playgroud)
编辑:这个项目的目的已暂停了一段时间,如果它再次没有得到解决,可能需要进行大量的重新思考.我离开了这个问题,因为我仍然对答案感兴趣.
是的,它们会兼容。这就是 s 的美妙之处struct。只要您不引入填充问题(正如您正确指出的那样,这里确实不会出现这种情况),或者在 C++ 中向 s 添加功能,struct这将导致 - 编译器特定的 - vtable 布局,这将是始终兼容。
您还会注意到,从 Windows 标头中,COM 接口的 C 声明使用structs 的方式与您的使用方式大致相同。
旁注:该SharedStreamInterface::destroy成员提出了一个问题:是否也有一个人可以“创建”这样的流。您可能也想分享这一点。但你的里程可能会有所不同......
至于调用约定的问题, 和__cdecl都__stdcall 应该跨二进制文件工作,但是我总是更喜欢__stdcall另一个原因:它比__cdecl.
对于样式:使用 a#define显式声明调用约定(就像您所做的那样),类似于WINAPIWindows 标头。