c 中的 fwrite() 以不同的顺序写入字节
fwrite() in c writes bytes in a different order
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *int_pointer = (int *) malloc(sizeof(int));
// open output file
FILE *outptr = fopen("test_output", "w");
if (outptr == NULL)
{
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
*int_pointer = 0xabcdef;
fwrite(int_pointer, sizeof(int), 1, outptr);
//clean up
fclose(outptr);
free(int_pointer);
return 0;
}
这是我的代码,当我看到带有 xxd 的 test_output 文件时,它给出了以下输出。
$ xxd -c 12 -g 3 test_output
0000000: efcdab 00 ....
我希望它打印 abcdef 而不是 efcdab。
使用htonl()
它将 host-byte-order 是什么(您机器的字节顺序)转换为网络字节顺序。因此,无论您 运行 在什么机器上,都将获得相同的字节顺序。使用这些调用是为了无论您 运行 在哪个主机上,字节都以正确的顺序通过网络发送,但它也适用于您。
参见 htonl and byteorder 的手册页。有各种可用的转换函数,也适用于不同的整数大小,16 位、32 位、64 位 ...
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
int main(void) {
int *int_pointer = (int *) malloc(sizeof(int));
// open output file
FILE *outptr = fopen("test_output", "w");
if (outptr == NULL) {
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
*int_pointer = htonl(0xabcdef); // <====== This ensures correct byte order
fwrite(int_pointer, sizeof(int), 1, outptr);
//clean up
fclose(outptr);
free(int_pointer);
return 0;
}
你在看哪本书?此代码中存在许多问题,例如将 malloc
的 return 值转换为......最重要的是,考虑使用整数类型的缺点,该整数类型的大小和表示形式可能因系统而异系统.
- 保证
int
能够存储介于 -32767 和 32767 之间的值。 您的实现可能允许更多值,但要 便携并且对使用古老编译器的人友好,比如Turbo C(有很多),你不应该使用int
来存储大于 32767 (0x7fff
) 的值,例如 0xabcdef
。当执行这样的out-of-range转换时,结果是implementation-defined;它可能涉及 saturation, wrapping, trap representations or raising a signal corresponding to computational error,例如,两者中的后者可能会在以后导致未定义的行为。
- 您需要转换成agreed-upon字段格式。当通过写方式发送数据,或者将数据写入文件以传输到其他系统时,它是重要的是要商定通信协议。这包括对整数字段使用相同的大小和表示。输出和输入都应该跟一个翻译函数(分别是序列化和反序列化)。
- 您的字段是二进制的,因此您的文件应该以二进制模式打开。 例如,使用
fopen(..., "wb")
而不是 "w"
。在某些情况下,'\n'
个字符可能会被翻译成一对 \r\n
个字符,否则; Windows 系统因此而臭名昭著。你能想象这会造成什么样的破坏和混乱吗?我可以,因为 I've answered a question about this problem.
也许 uint32_t
可能是更好的选择,但我会选择 unsigned long
,因为 uint32_t
不一定存在。关于这一点,对于没有 htonl
的系统(根据 POSIX,returns uint32_t
),该功能可以像这样实现:
uint32_t htonl(uint32_t x) {
return (x & 0x000000ff) << 24
| (x & 0x0000ff00) << 8
| (x & 0x00ff0000) >> 8
| (x & 0xff000000) >> 24;
}
作为受上述 htonl
函数启发的示例,请考虑以下宏:
typedef unsigned long ulong;
#define serialised_long(x) serialised_ulong((ulong) x)
#define serialised_ulong(x) (x & 0xFF000000) / 0x1000000 \
, (x & 0xFF0000) / 0x10000 \
, (x & 0xFF00) / 0x100 \
, (x & 0xFF)
typedef unsigned char uchar;
#define deserialised_long(x) (x[3] <= 0x7f \
? deserialised_ulong(x) \
: -(long)deserialised_ulong((uchar[]) { 0x100 - x[0] \
, 0xFF - x[1] \
, 0xFF - x[2] \
, 0xFF - x[3] })
#define deserialised_ulong(x) ( x[0] * 0x1000000UL \
+ x[1] * 0x10000UL \
+ x[2] * 0x100UL \
+ x[3] )
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *f = fopen("test_output", "wb+");
if (f == NULL)
{
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
ulong value = 0xABCDEF;
unsigned char datagram[] = { serialised_ulong(value) };
fwrite(datagram, sizeof datagram, 1, f);
printf("%08lX serialised to %02X%02X%02X%02X\n", value, datagram[0], datagram[1], datagram[2], datagram[3]);
rewind(f);
fread(datagram, sizeof datagram, 1, f);
value = deserialised_ulong(datagram);
printf("%02X%02X%02X%02X deserialised to %08lX\n", datagram[0], datagram[1], datagram[2], datagram[3], value);
fclose(f);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *int_pointer = (int *) malloc(sizeof(int));
// open output file
FILE *outptr = fopen("test_output", "w");
if (outptr == NULL)
{
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
*int_pointer = 0xabcdef;
fwrite(int_pointer, sizeof(int), 1, outptr);
//clean up
fclose(outptr);
free(int_pointer);
return 0;
}
这是我的代码,当我看到带有 xxd 的 test_output 文件时,它给出了以下输出。
$ xxd -c 12 -g 3 test_output
0000000: efcdab 00 ....
我希望它打印 abcdef 而不是 efcdab。
使用htonl()
它将 host-byte-order 是什么(您机器的字节顺序)转换为网络字节顺序。因此,无论您 运行 在什么机器上,都将获得相同的字节顺序。使用这些调用是为了无论您 运行 在哪个主机上,字节都以正确的顺序通过网络发送,但它也适用于您。
参见 htonl and byteorder 的手册页。有各种可用的转换函数,也适用于不同的整数大小,16 位、32 位、64 位 ...
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
int main(void) {
int *int_pointer = (int *) malloc(sizeof(int));
// open output file
FILE *outptr = fopen("test_output", "w");
if (outptr == NULL) {
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
*int_pointer = htonl(0xabcdef); // <====== This ensures correct byte order
fwrite(int_pointer, sizeof(int), 1, outptr);
//clean up
fclose(outptr);
free(int_pointer);
return 0;
}
你在看哪本书?此代码中存在许多问题,例如将 malloc
的 return 值转换为......最重要的是,考虑使用整数类型的缺点,该整数类型的大小和表示形式可能因系统而异系统.
- 保证
int
能够存储介于 -32767 和 32767 之间的值。 您的实现可能允许更多值,但要 便携并且对使用古老编译器的人友好,比如Turbo C(有很多),你不应该使用int
来存储大于 32767 (0x7fff
) 的值,例如0xabcdef
。当执行这样的out-of-range转换时,结果是implementation-defined;它可能涉及 saturation, wrapping, trap representations or raising a signal corresponding to computational error,例如,两者中的后者可能会在以后导致未定义的行为。 - 您需要转换成agreed-upon字段格式。当通过写方式发送数据,或者将数据写入文件以传输到其他系统时,它是重要的是要商定通信协议。这包括对整数字段使用相同的大小和表示。输出和输入都应该跟一个翻译函数(分别是序列化和反序列化)。
- 您的字段是二进制的,因此您的文件应该以二进制模式打开。 例如,使用
fopen(..., "wb")
而不是"w"
。在某些情况下,'\n'
个字符可能会被翻译成一对\r\n
个字符,否则; Windows 系统因此而臭名昭著。你能想象这会造成什么样的破坏和混乱吗?我可以,因为 I've answered a question about this problem.
也许 uint32_t
可能是更好的选择,但我会选择 unsigned long
,因为 uint32_t
不一定存在。关于这一点,对于没有 htonl
的系统(根据 POSIX,returns uint32_t
),该功能可以像这样实现:
uint32_t htonl(uint32_t x) {
return (x & 0x000000ff) << 24
| (x & 0x0000ff00) << 8
| (x & 0x00ff0000) >> 8
| (x & 0xff000000) >> 24;
}
作为受上述 htonl
函数启发的示例,请考虑以下宏:
typedef unsigned long ulong;
#define serialised_long(x) serialised_ulong((ulong) x)
#define serialised_ulong(x) (x & 0xFF000000) / 0x1000000 \
, (x & 0xFF0000) / 0x10000 \
, (x & 0xFF00) / 0x100 \
, (x & 0xFF)
typedef unsigned char uchar;
#define deserialised_long(x) (x[3] <= 0x7f \
? deserialised_ulong(x) \
: -(long)deserialised_ulong((uchar[]) { 0x100 - x[0] \
, 0xFF - x[1] \
, 0xFF - x[2] \
, 0xFF - x[3] })
#define deserialised_ulong(x) ( x[0] * 0x1000000UL \
+ x[1] * 0x10000UL \
+ x[2] * 0x100UL \
+ x[3] )
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *f = fopen("test_output", "wb+");
if (f == NULL)
{
fprintf(stderr, "Could not create %s.\n", "test_output");
return 1;
}
ulong value = 0xABCDEF;
unsigned char datagram[] = { serialised_ulong(value) };
fwrite(datagram, sizeof datagram, 1, f);
printf("%08lX serialised to %02X%02X%02X%02X\n", value, datagram[0], datagram[1], datagram[2], datagram[3]);
rewind(f);
fread(datagram, sizeof datagram, 1, f);
value = deserialised_ulong(datagram);
printf("%02X%02X%02X%02X deserialised to %08lX\n", datagram[0], datagram[1], datagram[2], datagram[3], value);
fclose(f);
return 0;
}