在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
什么会导致这种情况发生?整个过程中还有更多的情况发生,但我认为仅共享第一部分就足以说明问题。
感谢您的阅读。
答案 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
指定了最小宽度;它不将结果限制为两位数。)
%hhx
是unsigned char
的正确转换说明符。 %x
用于unsigned int
。
答案 1 :(得分:0)
格式说明符%02x
指定要输出的最小数字位数,而不是最大位数。当将值a4
,8b
和ef
解释为带符号字节时,它们均为负数,因此您所看到的是这些值的二进制补码,表示为32位{{1} },这就是它们传递给int
时的提升。
将缓冲区名称明确命名为printf
或unsigned char
,以避免这种意外的符号扩展,并使用正确的格式说明符(uint8_t
用于小写的%hhx
-{{1} }十六进制数字,a
为大写字母。