如何 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 写入小端,而无需进行一些复杂的检查以查看当前系统是否为大端,然后在 fwriting 之前反转位。
另一个想法是将它作为 ascii 存储在文件中,这没什么大不了的,它只是将 4 个字节变成了 8 个字节(十六进制)。但我认为这只是一个懒惰的解决方案。
我想从可能不同的机器上 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);
}
fwrite 一个整数取决于字节顺序,但是有没有一种方法可以将一个整数 0x00000004 写入一个文件,这样它就可以始终被读取为 0x00000004,而不管它 运行 在什么机器上。
一个想法是写第一位,然后是第二位,然后是第三位,总是按照特定的顺序,比如使用模数或位移来获取每个十进制值。
不确定是否有一种方法可以强制 fwrite 写入小端,而无需进行一些复杂的检查以查看当前系统是否为大端,然后在 fwriting 之前反转位。
另一个想法是将它作为 ascii 存储在文件中,这没什么大不了的,它只是将 4 个字节变成了 8 个字节(十六进制)。但我认为这只是一个懒惰的解决方案。
我想从可能不同的机器上 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);
}