7

Estoy trabajando en una biblioteca que permite a sus usuarios (otras bibliotecas que residen en el mismo proceso) intercambiar almacenamientos intermedios y flujos de datos. La biblioteca tiene que ser utilizable tanto desde MSVC como desde el código mingw (la mayor compatibilidad no duele, pero no es estrictamente necesaria). Para lograr esto, la funcionalidad central debe proporcionarse desde una pequeña interfaz compatible con el compilador que luego se puede ocultar mediante una capa de conveniencia compilada con el código del cliente.¿Es esta interfaz binaria compatible entre MSVC y mingw?

Un aspecto desafiante de la biblioteca es que debe ser extensible para que los clientes puedan proporcionar sus propias implementaciones de búfer y secuencia, pero la interfaz de la biblioteca central debe permanecer estable una vez que se lance. Si está interesado en más antecedentes, puede leer sobre esto en el forum thread discussion.

He intentado aprender sobre los problemas de compatibilidad binaria entre los compiladores, pero como soy nuevo en este tema, me interesarían los comentarios sobre mi resultado. No estoy interesado en el comportamiento definido por los estándares aquí (las estructuras probablemente fallan en esa prueba), solo en compatibilidad entre mingw y MSVC y quizás otros compiladores si es conveniente.

En particular, ¿las estructuras serán compatibles? Consisten de manera uniforme en indicadores de función, por lo que no creo que el relleno sea un problema. Además, ¿es necesaria aquí la convención estándar o funcionaría igual de bien? ¿Podría dejarlo sin especificar porque ambos compiladores usarán cdecl por defecto? ¿Debería? Aquí es lo que tengo en este momento:

#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); 
} 

Editar: El proyecto esta era para ha estado en espera desde hace un tiempo y probablemente necesita una gran cantidad de repensar si es cada vez unshelved nuevo. Sin embargo, estoy dejando la pregunta, porque todavía estoy interesado en la respuesta.

+0

Usaría definiciones condicionales para aquellos que llaman convs, porque bajo MSVC, no es seguro suponer que va a '' __cdecl', ya que puede anularse fácilmente con la configuración del proyecto. – Necrolis

Respuesta

3

Sí, serán compatibles. Esa es la belleza con struct s. Siempre que no introduzca problemas de relleno (que de hecho no serían el caso aquí, como señaló correctamente), o en C++, agregue la funcionalidad al struct que resultará en compilaciones específicas del compilador, esto hará ser siempre compatible.

También observará que desde los encabezados de Windows las declaraciones C de las interfaces COM usan struct s de la misma manera que usted.

Side-nota: el miembro SharedStreamInterface::destroy plantea la cuestión de si existe también uno de "crear" tal corriente. Usted puede querer compartir eso también. Sin embargo, su kilometraje puede variar ...

En cuanto a la cuestión de la convención de llamada, tanto __cdecl y __stdcalldebe trabajo a través de los binarios, sin embargo yo siempre prefieren __stdcall por otra razón: es compatible con más idiomas" "(es decir, herramientas) que __cdecl.

Para el estilo: utilice un #define para declarar el convenio de llamada explícitamente (como lo hace) similar a WINAPI desde los encabezados de Windows.

Cuestiones relacionadas