如何 fwrite 和 fread endianness independent integers,这样我就可以在许多机器上 fwrite 和 fread 并且总是有相同的结果

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 一个整数取决于字节顺序,但是有没有一种方法可以将一个整数 0x00000004 写入一个文件,这样它就可以始终被读取为 0x00000004,而不管它 运行 在什么机器上。

我想从可能不同的机器上 fwrite 和 fread,所以这两个操作都需要能够 fwrite 和 fread 相同的字节序,我不确定(在搜索这个站点之后)以一种可移植的方式来做到这一点(不使用某些机器上可能有也可能没有的晦涩库)。

我认为您无需担心位级字节序,我认为它们始终相同 how is data stored at bit level according to "Endianness"?

我可能会使用固定字节序来存储数据,并为 fread 和 fwrite 制作一些包装函数。

假设您决定将所有内容存储在小端,包装器将检查机器字节顺序并且:

  • 如果机器是little endian,直接使用fread和fwrite。
  • 如果机器是大端,相应地交换字节。显然,您会假设仅 int 对齐 reads/writes(如果您混合使用不同的长度类型,您的包装器将无法知道要交换哪些字节)。

EDIT 例如,您的 fwrite 可能看起来像这样(虽然没有测试,只是为了说明这个想法)。来自 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);
    }  
}

我刚刚将这个简单的字节序交换 fwrite。适用于任何字节顺序,只要你想交换字节顺序就可以使用它。适用于每个元素大小并且不会更改原始数据:

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;
}

小即兴

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
static size_t lendian_fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream)
{
    int x = 1;

    if ( *((char*)&x) == 1)
    {
        /* Little endian machine, use fwrite directly */
        return fwrite(ptr, size, nmemb, stream);
    }
    else
    {
        if(size == sizeof(uint8_t))     //1 Byte
        {
            return fwrite(ptr, size, nmemb, stream);
        }
        else if(size == sizeof(uint16_t))   //2 Byte
        {
            /* Big endian machine, pre-process first */
            unsigned char *buffer = malloc(size*nmemb);
            unsigned char *input = (unsigned char*) ptr;

            for (uint32_t i=0; i<nmemb; i++)
            {           
                buffer[2*i] = input[2*i + 1];
                buffer[2*i + 1] = input[2*i];
            }
            int ret =fwrite((void*)buffer, size, nmemb, stream);      
            free(buffer);
            return ret;
        }
        else if(size == sizeof(uint32_t)) //4 Byte
        { 
            /* Big endian machine, pre-process first */
            unsigned char *buffer = malloc(size*nmemb);
            unsigned char *input = (unsigned char*) ptr;

            for (uint32_t i=0; i<nmemb; i++)
            {           
                buffer[4*i    ] = input[4*i + 3];
                buffer[4*i + 1] = input[4*i + 2];
                buffer[4*i + 2] = input[4*i + 1];
                buffer[4*i + 3] = input[4*i    ];
            }

            int ret =fwrite((void*)buffer, size, nmemb, stream);      
            free(buffer);
            return ret;
        }
        else if(size == sizeof(uint64_t)) //8 Byte
        { 
            /* Big endian machine, pre-process first */
            unsigned char *buffer = malloc(size*nmemb);
            unsigned char *input = (unsigned char*) ptr;

            for (uint32_t i=0; i<nmemb; i++)
            {           
                buffer[8*i    ] = input[4*i + 7];
                buffer[8*i + 1] = input[4*i + 6];
                buffer[8*i + 2] = input[4*i + 5];
                buffer[8*i + 3] = input[4*i + 4];
                buffer[8*i + 4] = input[4*i + 3];
                buffer[8*i + 5] = input[4*i + 2];
                buffer[8*i + 6] = input[4*i + 1];
                buffer[8*i + 7] = input[4*i    ];
            }

            int ret =fwrite((void*)buffer, size, nmemb, stream);      
            free(buffer);
            return ret;
        }
        else
        {
            printf("%s Function received invalid element size:%ld\n",__FUNCTION__,size);
            return -1;
        }
 
    }  
}


int main()
{
    
    uint8_t  buf1[8] = { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 };
    uint16_t buf2[4] = { 0x1122,0x3344,0x5566,0x7788 };
    uint32_t buf3[2] = { 0x11223344, 0x55667788 };
    uint64_t buf4 = { 0x1122334455667788 };

    FILE *ofp = NULL;
    
    if((ofp=fopen("file.bin","wb"))==NULL)
    {
        printf("Cannot open output file!");
        return -1;
    }

    lendian_fwrite(&buf1, sizeof(uint8_t),sizeof(buf1),ofp);
    lendian_fwrite(&buf2, sizeof(uint16_t),sizeof(buf2)/sizeof(uint16_t),ofp);
    lendian_fwrite(&buf3, sizeof(uint32_t),sizeof(buf3)/sizeof(uint32_t),ofp);
    lendian_fwrite(&buf4, sizeof(uint64_t),sizeof(buf4)/sizeof(uint64_t),ofp);

    fclose(ofp);

}