C 中的 Hexdump 值太大

问题描述

我在 ./ 下有一个 MIDI 文件“USSR.mid”(二进制文件),我试图以 hexdump 的方式读取它,但得到了一些奇怪的输出

#include <stdio.h>

int main() {
    char buff[1000];
    FILE * midi_file = fopen("./USSR.mid","rb");
    fread(buff,1,900,midi_file);
    int i = 0;
    while(i<400) {
        printf("%02x ",buff[i]);
        i++;
    }
    fclose(midi_file);
    return 0;
}

我注意到某些值太大且不可读:

$ ./a.out 
4d 54 68 64 00 00 00 06 00 01 00 02 01 00 4d 54 72 6b 00 00 00 2b 00 ffffffff 58 04 04 02 18 08 00 ffffffff 59 02 fffffffe 00 00 ffffffff 03 0d 63 6f 6e 74 72 6f 6c 20 74 72 61 63 6b ffffff87 00 ffffffff 51 03 09 27 ffffffc0 01 ffffffff 2f 00 4d 54 72 6b 00 00 20 50 ffffff87 00 ffffffb0 79 00 00 ffffffb0 40 00 00 ffffffb0 5b 30 00 ffffffb0 0a 33 00 ffffffb0 07 64 00 ffffff90 41 53 00 ffffffb0 79 00 00 ffffffb0 40 00 00 ffffffb0 5b 30 00 ffffffb0 0a 33 00 ffffffb0 07 64 00 ffffffff 03 05 50 69 61 6e 6f ffffff81 00 ffffff80 41 00 00 ffffff90 3a 7f 00 ffffff90 3e 7f 00 ffffff90 41 7f 00 ffffff90 46 7f 00 ffffff90 22 7f 00 ffffff90 2e 7f ffffff82 00 ffffff80 3a 00 00 ffffff80 3e 00 00 ffffff80 41 00 00 ffffff80 46 00 00 ffffff90 3a 7f 00 ffffff90 3e 7f 00 ffffff90 41 7f 00 ffffff80 22 00 00 ffffff80 2e 00 00 ffffff90 22 7f 00 ffffff90 2e 7f ffffff81 40 ffffff80 41 00 00 ffffff90 43 7f 40 ffffff80 3a 00 00 ffffff80 3e 00 00 ffffff80 43 00 00 ffffff90 39 7f 00 ffffff90 3e 7f 00 ffffff90 41 7f 00 ffffff90 45 7f 00 ffffff80 22 00 00 ffffff80 2e 00 00 ffffff90 26 7f 00 ffffff90 32 7f ffffff82 00 ffffff80 39 00 00 ffffff80 3e 00 00 ffffff80 41 00 00 ffffff80 45 00 00 ffffff90 3e 7f 00 ffffff90 35 7f 00 ffffff90 39 7f 00 ffffff80 26 00 00 ffffff80 32 00 00 ffffff90 26 7f 00 ffffff90 32 7f ffffff81 00 ffffff80 3e 00 00 ffffff90 3e 7f ffffff81 00 ffffff80 35 00 00 ffffff80 39 00 00 ffffff80 3e 00 00 ffffff90 37 7f 00 ffffff90 3a 7f 00 ffffff90 43 7f 00 ffffff80 26 00 00 ffffff80 32 00 00 ffffff90 27 7f 00 ffffff90 33 7f ffffff82 00 ffffff80 37 00 00 ffffff80 3a 00 00 ffffff80 43 00 00 ffffff90 37 7f 00 ffffff90 3a 7f 00 ffffff90 41 7f 00 ffffff80 27 00 00 ffffff80 33 00 00 ffffff90 27 7f 00 ffffff90 33 7f ffffff81 40 ffffff80 37 00 00 ffffff80 3a 00 00 % 

里面有一堆“ffffXX”值。为什么会这样?

解决方法

为什么会这样?

代码没有使用匹配的打印说明符 "%x" 与对象类型(char,可能类似于 signed char)和值(一些负数)。

char buff[1000];
...
printf("%02x ",buff[i]);

"%x" 匹配 unsigned (C17dr § 7.21.6.1 8) 并且当值也在 int 范围内时也将与 unsigned 一起使用。 (C17dr § 6.5.2.2 6)

形式上,OP 的结果是未定义行为(UB)。

未定义行为在这里肯定发生的是 buff[] 为负数(例如 -1)并且 printf() 将该值解释为 unsigned 0xFFFFFFFF。


相反,由于代码想要查看 2 个字符的十六进制值,请使用 unsigned char 而不是 char

int main() {
    // char buff[1000];
    unsigned char buff[1000];
    FILE * midi_file = fopen("./USSR.mid","rb");
    int length = fread(buff,1,sizeof buff,midi_file);
    int i = 0;
    while(i < length) {
        printf("%02x ",buff[i]);
        i++;
    }
    ...