我正在编写一个打印" hexdump"一个给定的文件。功能如下:
bool printhexdump (FILE *fp) {
long unsigned int filesize = 0;
char c;
if (fp == NULL) {
return false;
}
while (! feof (fp)) {
c = fgetc (fp);
if (filesize % 16 == 0) {
if (filesize >= 16) {
printf ("\n");
}
printf ("%08lx ", filesize);
}
printf ("%02hx ", c);
filesize++;
}
printf ("\n");
return true;
}
但是,在某些文件中,似乎会打印某些无效的整数表示形式,例如:
00000000 4d 5a ff90 00 03 00 00 00 04 00 00 00 ffff ffff 00 00
00000010 ffb8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00 00 00 00 00 ff80 00 00 00
00000040 ffff
除了因ffff
字符而导致的上一个EOF
,ff90
,ffff
,ffb8
等都是错误的。但是,如果我将char
更改为unsigned char
,我会得到正确的表示形式:
00000000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00
00000010 b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00
00000040 ff
为什么上述行为会发生?
修改:c
对printf()
的处理方式应该相同,因为格式说明符不会更改。所以我不确定在char
获胜的情况下,unsigned char
如何延长签名?
答案 0 :(得分:3)
问:c
对printf()
的处理应该相同,因为格式说明符不会改变。
答:OP是正确的,c
对printf()
的处理没有改变。改变的是传递给printf()
的内容。在char
或unsigned char
时,c
通常会通过int
整数促销。 char
,如果已签名,则会获得一个符号扩展名。像0xFF这样的char
值是-1。 {0x}之类的unsigned char
值仍为255。
问:所以我不确定在char
赢得“{1}}”时,unsigned char
如何延长签名?
答:他们都有一个符号扩展名。 char
可能是否定的,因此其符号扩展名可以是0
或1
位。 unsigned char
始终为正,因此其符号扩展名为0
位。
解决方案
char c;
printf ("%02x ", (unsigned char) c);
// or
printf ("%02hhx ", c);
// or
unsigned char c;
printf ("%02x ", c);
// or
printf ("%02hhx ", c);
答案 1 :(得分:2)
char
可以是签名类型,在这种情况下,值0x80
到0xff
会在传递给printf
之前进行符号扩展。
(char)0x80符号扩展为-128,无符号短符为0xff80。
[编辑]更清楚宣传;存储在char中的值是8位,并且在该8位表示中,类似0x90的值将表示-112或114,这取决于char是有符号还是无符号。这是因为最高有效位作为有符号类型的符号位,而无符号类型的幅度位。如果该位置位,则它使值为负(通过减去128)或使其变大(通过加128),具体取决于它是否为带符号类型。
从char到int的升级总是会发生,但如果char被签名然后将其转换为int,则需要将符号位展开到int的符号位,以便int表示与char相同的值。
然后printf
得到它,但是不知道原始类型是签名还是未签名,并且它不知道它曾经是一个字符。它所知道的是格式说明符是无符号的十六进制短,因此它打印该数字就好像它是无符号短。 16位int
中-112的位模式为1111111110010000
,格式为十六进制,即ff90。
如果您的char是无符号的,则0x90不表示负值,当您将其转换为int时,无需在int中更改任何内容以使其表示相同的值。位模式的其余部分全为零,printf
不需要那些正确显示数字。
答案 2 :(得分:1)
问题只是由格式引起的。 %h02x
采用int。当你把一个低于128的字符时,一切都很好,它是正的,转换为int时不会改变。
现在,让我们拿一个128以上的字符,说0x90
。作为unsigned char,它的值为144,它将转换为int值144,并打印在90
。但作为一个带符号的char,它的值为-112(仍为0x90),它将转换为值为-112的int(对于16位int为0xff90)并打印为ff90
。
答案 3 :(得分:0)
因为在unsigned char
中,最重要的位与signed char
的含义不同。
例如,二进制文件中的0x90
为10010000
,144
十进制,无符号,但签名为-16
十进制。
答案 4 :(得分:0)
char
是否已签名取决于平台。这意味着根据您的机器可能会或可能不会扩展符号位,因此您可以得到不同的结果。
但是,使用unsigned char
可确保没有符号扩展名(因为不再有符号位)。