7

I have a code which is compiled into a library (dll, static library and so). I want the user of this library to use some struct to pass some data as parameters for the library function. I thought about declaring the struct in the API header file.

  • Is it safe to do so, considering compilation with different compilers, with respect to structure alignment or other things I didn't think about?
  • Will it require the usage of the same compiler (and flags) for both the library and its user?

Few notes:

  1. I considered giving the user a pointer and set all the struct via functions in the library, but this will make the API really not comfortable to use.
  2. This question is about C, although it would be nice to know if there's a difference in c++.
MByD
  • 135,866
  • 28
  • 264
  • 277

2 Answers2

3

If it's a regular/static library, the library and application should be compiled using the same compiler. There're a few reasons for this that I can think of:

  1. Different compilers (as in different brands or compilers for different platforms) normally don't understand each other's object and library formats.
  2. You don't want to compile different parts of the same program using different types (e.g. signed vs unsigned char), type sizes (e.g. long = 32 vs 64 bits), alignment and packing and probably some other things, all of which are allowed by the C standard to vary. Mixing and matching those things is usually a bad thing.

You may, however, often use slightly different versions of the same compiler to compile the library and the application using it. Usually, it's OK. Sometimes there're changes that break the code, though.

You may implement some "initialization" function in that header file (declared as static inline) that would ensure that types, type sizes, alignment and packing are the same as expected by the compiled library. The application using this library would have to call this function prior to using any other part of the library. If things aren't the same as expected, the function must fail and cause program termination, possibly with some good textual description of the failure. This won't solve completely the problem of having somewhat incompatible compilers, but it can prevent silent and mysterious malfunctions. Some things can be checked with the preprocessor's #if and #ifdef directives and cause compilation errors with #error.

In addition, structure packing problems can be relieved by inserting explicit padding bytes into structure declarations and forcing tight packing (by e.g. using #pragma pack, which is supported by many compilers). That way if type sizes are the same, it won't matter what the default packing is.

You can apply the same to DLLs as well, but you should really expect that the calling application has been compiled with a different compiler and not depend on the compilers being the same.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
0

All Windows APIs throw structs around like crazy so obviously this is something that is done every day and it works. Of course it doesn't mean that your concerns are not valid :) I would suggest making your structure's fields have explicit width types (int32_t etc) and maybe specify explicitly that that the packing in a way which would break on any compiler but yours, i.e.

#if defined(_MSC_VER)
#pragma pack(0)
#elif defined ... handle gcc
#else
FAIL // fail compilation on unsupported platform
#endif
MK.
  • 33,605
  • 18
  • 74
  • 111
  • The Windows APIs *definitely* define packing explicitly for their structures. They just encapsulate/obfuscate it all away in headers. You are *probably* safe doing this, but exercising care is thoroughly encouraged. – Cody Gray - on strike Dec 18 '11 at 05:15