7

我正在研究一個庫,允許其用戶(駐留在同一進程中的其他庫)交換數據緩衝區和流。該庫必須可以從MSVC和mingw代碼中使用(更多兼容性不會受到傷害,但並非絕對必要)。爲了實現這一點,核心功能應該由一個小的,兼容編譯器的接口提供,稍後可以通過用客戶端代碼編譯的便利層隱藏。MSVC和mingw之間的界面二進制兼容嗎?

圖書館所面對的挑戰是,它必須是可擴展的,這樣客戶可以提供自己的緩衝區和流實現,但是一旦它被釋放的核心庫的接口必須保持穩定。如果您對進一步的背景感興趣,可以在forum thread discussion中閱讀。

我試圖瞭解編譯器之間的二進制兼容性的問題,但由於我是新來這個話題我有興趣在我的結果的意見。我對這裏的標準定義行爲不感興趣(結構可能無法通過該測試),只有在兼容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); 
} 

編輯:這是爲那些已經擱置了一段時間了,可能該項目需要大量的重新思考,如果這是有史以來unshelved再次的。儘管如此,我仍然留下了這個問題,因爲我仍然對答案感興趣。

+0

我會使用條件規定了那些呼籲convs,MSVC下造成的,它不是安全的假設,它會默認爲'__cdecl',因爲這可以很容易地與項目設置進行覆蓋。 – Necrolis 2011-05-22 11:21:38

回答

3

是的,它們將是兼容的。這是與struct s的美。只要你沒有引入填充問題(在你正確指出的情況下,這確實不是這種情況),或者在C++中添加功能到struct,這將導致 - 編譯器特定的-vtable佈局,這將會始終兼容。

你還會注意到,從Windows頭的COM接口的C聲明使用struct S IN多,你做同樣的方式。

側面說明:在SharedStreamInterface::destroy成員引出了一個問題,即是否也有一個「創造」這樣一個流。你可以也可以也想分享。但是你的里程可能會有所不同...

至於調用約定的問題,既__cdecl__stdcall應在整個二進制工作,但我總是喜歡__stdcall的另一個原因是:它是與更多的「語言兼容「(即工具)比__cdecl

對於樣式:使用#define來明確聲明調用約定(與您一樣),類似於Windows頭文件中的WINAPI