jake jake - 1 month ago 12
C Question

How to fwrite and fread endianness independant integers, such that I can fwrite and fread on many machines and always have the same result

fwrite an integer depends on endianness, but is there a way to write an integer 0x00000004 to a file such that it can be fread always as 0x00000004 regardless of machine it's run on.


  • One thought is to write the first bit, then second, then third always in a specific order,such as grabbing each decimal value using modulus or bit shifting.

  • Not sure if there's a way to force fwrite to write as little endian without having some convoluted check to see if the current system is big endian, and then reversing the bits before fwriting.

  • Another thought is to store it in the file as ascii, which isn't a huge deal it just turns 4 bytes into maybe 8 (hex). But I figure this is just a lazy solution.



I want to fwrite and fread from possibly different machines, so both operations need to be able to fwrite and fread the same endianness, and I'm not sure (after searching this site) on a portable way to do this (without using some obscure library that may or may not be on certain machines).

Answer

I don't think you need to worry about bit-level endianness, I think they are always the same how is data stored at bit level according to "Endianness"?

I would probably use a fixed endiannes to store the data, and make some wrapper functions for fread and fwrite.

So say you decide to store everything in little endian, the wrappers would check the machine endianness and:

  • If the machine is little endian, use fread and fwrite directly.
  • If the machine is big endian, swap bytes accordingly. Obviously, you would be assuming int-only aligned reads/writes (if you mix different length types, your wrapper will have no way to know which bytes to swap).

EDIT E.g., your fwrite could look like this (not tested though, just to illustrate the idea). Endianness check from C program to check little vs. big endian:

size_t lendian_fwrite(const void *ptr, size_t size, size_t nmemb,
                     FILE *stream)
{
    if (size != 4)
    {
        /* Warn and exit */
    }

    int x = 1;

    if ( *((char*)&x) == 1)
    {
        /* Little endian machine, use fwrite directly */
        return fwrite(ptr, size, nmemb, stream);
    }
    else
    {
        /* Big endian machine, pre-process first */

        unsigned char *buffer = (unsigned char*) ptr;

        for (int i=0; i<nmemb; i++)
        {           
            unsigned char a = buffer[4*i];
            unsigned char b = buffer[4*i + 1];

            buffer[4*i] = buffer[4*i + 3];
            buffer[4*i + 1] = buffer[4*i + 2];
            buffer[4*i + 2] = b;
            buffer[4*i + 3] = a;
        }

        return fwrite(ptr, size, nmemb, stream);
    }  
}
Comments