3
struct my_struct
{
  char  a;
  short b;
  int   c;
};

sizeof(my_struct) may vary on different machines (size of any standard c++ type may vary in particular). It depends from memory alignment as well (#pragma pack(*) etc.). What would be the best way of implementing fixed size struct?

Ivars
  • 2,375
  • 7
  • 22
  • 31
  • @herohuyongtao i want to read and write it to a file. created files won't work with apllication compiled on different machine since size of my_struct would be different. – Ivars Jan 13 '14 at 14:50
  • 1
    @herohuyongtao: It is very common to need to control and know the size of structures in inter-process communication. This is doubly true when communicating over a network with machines running varying operating systems and you don't want to express everything as strings. – John Dibling Jan 13 '14 at 15:11

3 Answers3

2

Nothing you can do will guarantee that a struct will have the same size on all possible implementations. About the closest you can probably get would be something like:

struct my_struct { 
    char contents[some_size];
};

This at least guarantees that the contents will be the same size on all implementations. The implementation is still free to insert padding after the contents though, so you could still get different sizes on different implementations.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • but what about reading or writing struct to a file? it has to be fixed size somehow. bitmap header struct has to be fixed size since size of its header is documented. – Ivars Jan 13 '14 at 14:39
  • What you write to a file doesn't need to match what's in memory. If you really care about portability, you typically write only individual fields out to the file, thus eliminating most possible padding (but even this doesn't give an absolute guarantee of portability). – Jerry Coffin Jan 13 '14 at 14:49
  • so using something like `DummyWrite(FileHandle, &my_struct, sizeof(my_struct))` would be wrong? What if I have thousands of fields? do i have to write all of them manually? That's horrible! – Ivars Jan 13 '14 at 14:55
  • @user2543574: If you have thousands of fields, you're doing something else wrong. Regardless of that, however, you could also consider any of various libraries intended to make this sort of job somewhat simpler (e.g., Google Protocol Buffers). – Jerry Coffin Jan 13 '14 at 15:33
2

If you can be somewhat realistic and knowledgeable about your target platforms, you can fairly easily find some common ground and use that as the basis for your structures.

For example, if your target platforms are Windows and Linux running on current x86 hardware, then you know a few things already:

  • char is exactly 1 byte per the Standard
  • 1 byte is 8 bits
  • int8_t and uint8_t are exactly 8 bits under C++11 (most C++03 compilers provide these anyway)
  • int16_t and uint16_t are exactly 16 bits under C++11
  • int32_t and uint32_t are exactly 32 bits under C++11
  • int64_t and uint64_t are exactly 64 bits under C++11
  • C-style ASCII strings are NULL-terminated char arrays
  • Preprocessor directives are available to take control over packing

Endianness will still be an issue, so you will have to deal with this when converting multi-byte types.

Trying to devise a structure which will be guaranteed by the Standard to have the same binary representation on the wire on all exotic platforms is impossible. You can get close by using only chars, but even then there is no guarantee because you don't know how many bits are in a byte.

You could try to use bitfields to represent your data, but you still don't know how many bits are in a byte so you can't be certian how much padding will be added at the end.

Portability serves a purpose: portable code is easier to maintain and extend than platform-specific code. Pursuing portability for portability's sake is an academic goal that has no place in professional programming. Pursuing portability for maintainability's sake on the other hand is a laudable goal, but it's also a balancing act. If you come up with a completely portable solution that is works on all possible platforms, but you will only run on two of those platforms and your code is impossible to maintain, then what is the point?

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • thanks! i have some struct that needs to be written to a file and read as well. if i want my project to be portable across several platforms does that mean that i have to implement struct for each platform? – Ivars Jan 13 '14 at 15:26
  • @user2543574: No. You would implement just *one* struct that only uses fields known to each platform. You will however have to implement endian conversions for each platform. – John Dibling Jan 13 '14 at 15:27
  • a little bit off-topic.. what's the difference between __int* and int*_t? – Ivars Jan 13 '14 at 15:38
  • `__int*` is platform-specific. `int*_t` is defined by the Standard. – John Dibling Jan 13 '14 at 15:50
  • huh? `__int32` isn't guaranteed to be 32-bits? what for it has `32` suffix? – Ivars Jan 13 '14 at 16:00
  • @user2543574: Do you know what I'm referring to when I say "the Standard?" – John Dibling Jan 13 '14 at 16:01
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45130/discussion-between-user2543574-and-john-dibling) – Ivars Jan 13 '14 at 16:02
1

You could pack your structure to have a deterministic size. Here is a link to implement that in a portable way: Visual C++ equivalent of GCC's __attribute__ ((__packed__))

Community
  • 1
  • 1
A. Lefebvre
  • 139
  • 4