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

4

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).

c
fwrite
endianness
fread
asked on Stack Overflow Oct 22, 2016 by jake

2 Answers

2

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);
    }  
}
answered on Stack Overflow Oct 22, 2016 by Luis de Arquer • edited May 23, 2017 by Community
0

I just made this simple endian swap fwrite. Works with any endianness, use it whenever you want the byte order swapped. Works for every element size and does not change the original data:

size_t endian_swap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
    unsigned char *buffer_src = (unsigned char*)ptr;
    unsigned char *buffer_dst = new unsigned char[size*nmemb];
    for (size_t i = 0; i < nmemb; i++)
    {
        for (size_t ix = 0; ix < size; ix++) {
            buffer_dst[size * i + (size - 1 - ix)] = buffer_src[size * i + ix];
        }
    }
    size_t result = fwrite(buffer_dst, size, nmemb, stream);
    delete buffer_dst;
    return result;
}
answered on Stack Overflow Jul 9, 2019 by thewhiteambit

User contributions licensed under CC BY-SA 3.0