Этот двоичный интерфейс совместим между MSVC и mingw? - PullRequest
7 голосов
/ 22 мая 2011

Я работаю над библиотекой, которая позволяет ее пользователям (другим библиотекам, находящимся в том же процессе) обмениваться буферами данных и потоками.Библиотеку нужно использовать как из кода 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);
}

Редактировать: проект, для которого это было предназначено, был приостановлен какое-то время и, вероятно, требует много переосмысления, если он когда-либо снова останется без работы.Я оставляю вопрос, хотя, потому что я все еще заинтересован в ответе.

1 Ответ

3 голосов
/ 29 марта 2012

Да, они будут совместимы.Это красота с struct с.До тех пор, пока вы не столкнетесь с проблемами заполнения (что на самом деле не будет так, как вы правильно указали), или в C ++ добавьте функциональность к struct s, которая приведет к компилятору - vtable layout,это всегда будет совместимо.

Вы также заметите, что из заголовков Windows объявления C-интерфейсов C используют struct s во многом так же, как и вы.

Примечание:член SharedStreamInterface::destroy задает вопрос, есть ли еще один, который "создает" такой поток.Вы можете также захотеть поделиться этим.Но ваш пробег может варьироваться ...

Что касается вопроса о соглашении о вызовах, то __cdecl и __stdcall должны работать через двоичные файлы, однако я бы всегда предпочел __stdcall по другой причине: он совместим с большим количеством "языков" (т. е. инструментов), чем __cdecl.

Для стиля: используйте #define, чтобы объявить соглашение о вызовах явно (как и вы), аналогично WINAPI из заголовков Windows.

...