views:

432

answers:

5

I realize that in general the C and C++ standards gives compiler writers a lot of latitude. But in particular it guarantees that POD types like C struct members have to be laid out in memory the same order that they're listed in the structs definition, and most compilers provide extensions letting you fix the alignment of members. So if you had a header that defined a struct and manually specified the alignment of its members, then compiled two apps with different compilers using the header, shouldn't one app be able to write an instance of the struct into shared memory and the other app be able to read it without errors?

I am assuming though that the size of the types contained is consistent across two compilers on the same architecture (it has to be the same platform already since we're talking about shared memory). I realize that this is not always true for some types (e.g. long vs. long long in GCC and MSVC 64-bit) but nowadays there are uint16_t, uint32_t, etc. types, and float and double are specified by IEEE standards.

+2  A: 

As long as you can guarantee the exact same memory layout, including offsets, and the data types have the same sizes between the 2 compilers then yes this is fine. Because at that point the struct is identical with respect to data access.

JaredPar
This sounds more like a no.
Trent
@Trent, <hand wavy motion/> It depends, if you can make these guarantees with horrible pragmas or corner cases of the language then sure it works. Making that guarantee is very hard though IMHO
JaredPar
@Trent: It's pretty much the same "yes but" response as for using structs to read/write data over the network. Using a struct to represent serialised/marshalled data is a detail of your app that might be convenient if you can guarantee the struct is correct. Binary data between different C implementations should probably be considered "serialised": whether it's shared over the network or in shared RAM, the same concerns apply that types and layout might not match. An array and a stream can both be thought of as a sequence of char.
Steve Jessop
At least with shared memory on the same host you don't have endian problems.
Mark B
A: 

The way memory is laid out is important in addition to the datatype size if you need struct from library 1 compiled by compiler 1 to be used in library 2 compiled by compiler 2.

wrapperm
A: 

It is indeed possible, you just have to make sure that all compilers involved generate the same data structure from the same code. One way to test this is to write a sample program that creates a struct and writes it to a binary file. Open the resulting files in a hex editor and verify that they are the same. Alternatively, you can cast the struct to an array of uint8_t and dump the individual bytes to the screen.

One way to make sure that the data sizes are the same is to use data types like int16_t (from stdint.h) instead of a plain old int which may change sizes between compilers (although this is rare on two compilers running on the same platform).

It's not as difficult as it sounds. There are many pre-compiled libraries out there that can be used with multiple compilers. The key thing is to build a test program that will let you verify that both compilers are treating the structure equally.

bta
A: 

Yes, sure. I've done this many times. The problems and solutions are the same whether mixed code is compiled and linked together, or when transmitting struct-formatted data between machines.

In the bad old days, this frequently occurred when integrating MS C and almost anything else: Borland Turbo C. DEC VAX C, Greenhills C.

The easy part is getting the number of bytes for various data types to agree. For example short on a 32-bit compiler on one side being the same as int on a 16-bit compiler at the other end. Since common source code to declare structures is usually a good thing, a number of to-the-point declarations are helpful:

typedef  signed long     s32;
typedef  signed short    s16;
typedef  signed char     s8;
typedef  unsigned long   u32;
typedef  unsigned short  u16;
typedef  unsigned char   u8;
...

Microsoft C is the most annoying. Its default is to pad members to 16-bit alignment, and maybe more with 64-bit code. Other compilers on x86 don't pad members.

struct {
    int   count;
    char  type;
    char  code;
    char  data [100];
} variable;

It might seem like the offset of code should be the next byte after type, but there might be a padding byte inserted between. The fix is usually

#ifdef _MSC_VER    // if it's any Microsoft compiler
 #pragma pack(1)   // byte align structure members--that is, no padding
#endif

There is also a compiler command line option to do the same.

wallyk
A: 

Refer to your compiler manuals.

most compilers provide extensions letting you fix the alignment of members

Are you restricting yourself to those compilers and a mutually compatible #pragma align style? If so, the safety is dictated by their specification.

In the interest of portability, you are possibly better off ditching #pragma align and relying on your ABI, which may provide a "reasonable" standard for compliance of all compilers of your platform.

As the C and C++ standards allow any deterministic struct layout methodology, they're essentially irrelevant.

Potatoswatter