Binary data compability in C structs

Note:Everything below is correct. But my idea was to let the struct members s1 and s2 be short, not int. A little mistake, that I might fix some day and update my findings.

What if you do the stupid thing: dump C-structs into a binary file on a computer with one architecture, and load it into another?

Well, I decided to make a little test. I wrote a little program in C that populates a struct with different datatypes and data, and writes the data to a file. I built and ran the program in different environments, with some success.

Summary
Be aware that this is not evidence for anything. Do not rely on this for anything important unless you back up with other facts or make tests in your platform.

The following appears to be compatible:

  1. QNAP 109 / armv5tel / Debian 6.0.8 / gcc version 4.4.5
  2. Raspberry Pi / Raspbmc / gcc 4.6.3
  3. Mac Book / Core 2 Duo / OS X 10.7.5 / gcc version 4.2.1 (LLVM build 2336.11.00)
  4. PC / Athlon 250 II X2 250 / Ubuntu 13.04 / gcc version 4.7.3

This one produced a slightly different output:

  1. HP Compaq 6910p / Core 2 Duo / Ubuntu 13.04 (32-bit) / gcc 4.7.3

The test program
This is the source of the test program I wrote.

#include <stdio.h>
#include <string.h>

struct data0 {
  char   b1[5];
  int    s1;
  int    i1;
  int    i2;
  int    i3;
  int    i4;
  float  f1;
  float  f2;
  int    s2;
  float  f3;
  long long l1;
  double d1;
};

int main() {
  struct data0 d0;
  FILE* fp;
  int n;

  strcpy(d0.b1, "ABCD");
  d0.s1    = 0x6543;
  d0.i1    = 0;
  d0.i2    = 0x11223344;
  d0.i3    = -1;
  d0.i4    = 0xffffffff;
  d0.f1    = 0.0;
  d0.f2    = 999.999;
  d0.s2    = 0x3456;
  d0.f3    = -777777.0;
  d0.l1    = 0x1122334455667788LL;
  d0.d1    = 1000.0;

  fp = fopen("out.bin", "w");
  n = fwrite(&d0, sizeof(struct data0), 1, fp);
  fclose(fp);

  printf("Bytes written=%d\n", 1 * sizeof(struct data0));
  printf("sizeof(short)=%d\n", sizeof(short));
  printf("sizeof(int)=%d\n", sizeof(int));
  printf("sizeof(long)=%d\n", sizeof(long));
  printf("sizeof(long long)=%d\n", sizeof(long long));
  printf("sizeof(float)=%d\n", sizeof(float));
  printf("sizeof(double)=%d\n", sizeof(double));

  return 0;
}

Note that there are intentional “holes” in the struct: Around s1. Around s2-f3. The holes are big enough allow for different possible variable alignments (how to do this is probably well specified somewhere).

Mac Book, Core 2 Duo, Mac OS X 10.7.5, gcc version 4.2.1 (LLVM build 2336.11.00)

$ ./bytes 
Bytes written=64
sizeof(short)=2
sizeof(int)=4
sizeof(long)=8
sizeof(long long)=8
sizeof(float)=4
sizeof(double)=8
$ xxd out.bin 
0000000: 4142 4344 007f 0000 4365 0000 0000 0000  ABCD....Ce......
0000010: 4433 2211 ffff ffff ffff ffff 0000 0000  D3".............
0000020: f0ff 7944 5634 0000 10e3 3dc9 0000 0000  ..yDV4....=.....
0000030: 8877 6655 4433 2211 0000 0000 0040 8f40  .wfUD3"......@.@

QNAP 109, Debian 6.0.8, gcc 4.4.5

$ ./bytes 
Bytes written=64
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(float)=4
sizeof(double)=8
$ xxd out.bin 
0000000: 4142 4344 009b 0040 4365 0000 0000 0000  ABCD...@Ce......
0000010: 4433 2211 ffff ffff ffff ffff 0000 0000  D3".............
0000020: f0ff 7944 5634 0000 10e3 3dc9 7483 0000  ..yDV4....=.t...
0000030: 8877 6655 4433 2211 0000 0000 0040 8f40  .wfUD3"......@.@

As far as I can see – this conforms 100% to the Mac Book above. The differences are all in undefined holes in the struct, that are aligned identically. Obviously, the “long” datatype is not usable.

HP Compaq 6910p, Core 2 Duo, Ubuntu 13.04 (32-bit), gcc 4.7.3

$ ./bytes 
Bytes written=60
sizeof(short)=2
sizeof(int)=4
sizeof(long)=4
sizeof(long long)=8
sizeof(float)=4
sizeof(double)=8
$ xxd out.bin 
0000000: 4142 4344 0084 0408 4365 0000 0000 0000  ABCD....Ce......
0000010: 4433 2211 ffff ffff ffff ffff 0000 0000  D3".............
0000020: f0ff 7944 5634 0000 10e3 3dc9 8877 6655  ..yDV4....=..wfU
0000030: 4433 2211 0000 0000 0040 8f40            D3"......@.@

Wow – suddenly a 64-bit long long is aligned differently, saving 4 bytes. Apart from alignments, all variables seem to be stored the same way.

Note / Warning
Note that structs that contain 8-byte-variables (doubles, longs) may (x64 and ARM) or may not (x86) be padded in the end to 8-byte-alignment. That means, even if all variables are aligned identically, sizeof(struct) may differ. This matters if you store/send/share an array of structs between two machines.

Conclusion
ARM and x86 appears to be byte compatible for integers (2,4,8 bytes), floats (4 bytes) and doubles (8 bytes). Be careful with structs with holes in them.

In controlled environments, it should be possible to take advantage of this.

Todo
I will try to build exe-files for 32- and 64-bit windows (using Microsoft compiler) – that will be interesting.

It would be interesting if someone could post results from an iOS device.

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Time limit is exhausted. Please reload CAPTCHA.