是什么导致读取二进制文件时0xA4变为0xffffffa4?

时间:2019-02-25 21:51:12

标签: c

在C中加载二进制文件时得到意外结果。

FILE *bin = NULL;
unsigned long file_length = 0;

bin = fopen("vs.bin", "rb");
fseek(bin, 0, SEEK_END);
file_length = ftell(bin);
fseek(bin, 0, SEEK_SET);

char *buffer = (char *)malloc(file_length);
fread(buffer, 1, file_length, bin);

for(unsigned int i = 0; i < file_length; i++) {
    printf("%02x ", buffer[i]);
}
printf("\n");

我在输出的前八个值中看到的是:

56 53 48 05 ffffffa4 ffffff8b ffffffef 49

但是当我在十六进制编辑器中打开二进制文件时,看到的是:

56 53 48 05 A4 8B EF 49

什么会导致这种情况发生?整个过程中还有更多的情况发生,但我认为仅共享第一部分就足以说明问题。

感谢您的阅读。

2 个答案:

答案 0 :(得分:7)

char *buffer更改为unsigned char *buffer。并将%02x更改为%02hhx

在您的C实现中,char已签名。当您将数据读入char的缓冲区中时,就具有带符号的值。在表达式中使用它们(包括printf的参数)时,其中一些具有负值。另外,通常将小于int的值提升为int。那时,char值−92(用0xA4位表示)变成了int值−92(在C实现中用位0xFFFFFFA4表示)。

因此,您具有负值,这些负值将转换为int,然后用%02x打印,并且%02x显示int的所有位。 (在%02x中,2指定了最小宽度;它不将结果限制为两位数。)

%hhxunsigned char的正确转换说明符。 %x用于unsigned int

答案 1 :(得分:0)

格式说明符%02x指定要输出的最小数字位数,而不是最大位数。当将值a48bef解释为带符号字节时,它们均为负数,因此您所看到的是这些值的二进制补码,表示为32位{{1} },这就是它们传递给int时的提升。

将缓冲区名称明确命名为printfunsigned char,以避免这种意外的符号扩展,并使用正确的格式说明符(uint8_t用于小写的%hhx-{{1} }十六进制数字,a为大写字母。