binary files on different computer with different word size

Mar 30, 2009 at 1:31am
Let's say I have a structure containing ints. I have 2 computers one which the size of an int is 16 bit and the other in which int is 32bits.

If I create a binary file containing that structure on the 16bit computer with a program compiled on it and transfer that file over to the 32bit computer, in which i use a compiled program on to read the file, what will happen?

I assume that it would not work, and if I am correct, is there any way to solve this problem?

Mar 30, 2009 at 1:48am
I generally typedef my own types which are an exact bitwidth. <stdint.h> has a bunch of these types, but apparently that's not standard (although I could've swore it was)

1
2
3
4
5
typedef unsigned char   u8;
typedef unsigned short  u16;
typedef unsigned long  u32;

// repeat for signed counterparts 


Alternatively you can use <stdint.h>'s uint8_t, uint16_t, etc.

Sizes of these can be confirmed with a sizeof() at program startup:

1
2
3
if(sizeof(u8) != 1)   throw "u8 wrong size";
if(sizeof(u16) != 2)   throw "u16 wrong size";
if(sizeof(u32) != 4)   throw "u32 wrong size";


Then, rather than writing an 'int' to a file, you write a fixed-size variable to a file instead. This will ensure it gets read properly on any platform because the appropriate size can be typedef'd to fit.

Another thing to watch for it endianness. Reading/writing multi-byte variables are subject to system endianness. ie: writing a 32-bit value 0x01020304 to a file on a little endian machine, then reading it back on a big endian machine will give you 0x04030201.

To solve this I wrote some template functions which break up the value and read/write it one byte at a time. These are for my personal file wrapper class, but you can get the jist of them and apply them to whatever file IO method you're using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
    template <typename T>
    bool PutInt(T v)
    {
        size_t i;
        u8 by;
        for(i = 0; i < sizeof(T); ++i)
        {
            by = (u8)(v >> (i*8));
            if(Write(&by,sizeof(u8)) <= 0)
                return false;
        }
        return true;
    }

    template <typename T>
    T GetInt(bool* isok = 0)
    {
        size_t i;
        T ret = 0;
        u8 by;
        for(i = 0; i < sizeof(T); ++i)
        {
            if(Read(&by,sizeof(u8)) <= 0)
            {
                if(isok)    *isok = false;
                return ret;
            }
            ret |= (T)by << (i*8);
        }
        if(isok)    *isok = true;
        return ret;
    }
///////////////////////////////////////
// to use

myfile.PutInt<u32>(5);  // write 5 to file in endian-safe manner

u32 something = myfile.GetInt<u32>();  // read from file 


I also have GetInts() and PutInts() which take an array... they just loop and call the above functions.

Reading/writing floating points in a safe way is another can of worms and is something I haven't really thought about yet because I haven't had need to do it yet.
Topic archived. No new replies allowed.