Вопрос

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

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

Это было полезно?

Решение

Да, они будут совместимы.Вот красота с structс.Пока вы не создаете проблемы с заполнением (чего здесь действительно не будет, как вы правильно заметили) или в C++ добавляете функциональность в structs, которые приведут к созданию макетов виртуальных таблиц (зависящих от компилятора), это всегда будет совместимо.

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

Примечание:тот SharedStreamInterface::destroy Участник задается вопросом, есть ли кто-нибудь, кто «создает» такой поток.Ты может хочу поделиться и этим.Но ваш пробег может отличаться...

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top