字符串比较中的十六进制文字问题

时间:2009-09-07 18:14:25

标签: c hex fopen strcmp

我正在读NES ROM文件,其中前四个字节是“\ x4e \ x45 \ x53 \ x1a”或NES \ x1a。在我的实际代码中,给定的文件可以是任意的,所以我想检查以确保此标头在这里。但是,我遇到了一些麻烦,以下代码演示了:

#include <stdio.h>
#include <string.h>

int main()
{
    FILE *fp;
    fp = fopen("mario.nes", "rb");

    char nes[4];
    char real_nes[4] = "NES\x1a";
    fread(nes, 4, 1, fp);
    printf("A: %x\n", nes[3]);
    printf("B: %x\n", real_nes[3]);
    printf("C: %s\n", nes);
    printf("D: %s\n", real_nes);
    if (strcmp(nes, real_nes) != 0) {
        printf("not a match\n");
    }
    fclose(fp);
    return 0;
}

返回:

A: 1a
B: 1a
C: NES?
D: NES
not a match

问号是\ x1a。

我是C的新手,所以我可能会遗漏一些微妙的(或明显的)两个字符串不匹配的原因,以及为什么在打印D行时没有显示问号,以表示\ x1a位于字符串的末尾,B行似乎表明它应该是。

5 个答案:

答案 0 :(得分:4)

一些评论和建议:

  • 以二进制模式打开文件 - 否则,非POSIX系统上可能会发生有趣的事情(已修复

    fp = fopen("mario.nes", "rb");
    
  • 如果要打印或比较缓冲区,请使用null终止缓冲区,或使用接受字符串长度作为额外参数的strncmp()等函数

    printf("C: %.4s\n", nes);
    printf("D: %.4s\n", real_nes);
    if (strncmp(nes, real_nes, 4) != 0) {
    
  • '\x1a'是非图形替代字符^Z

  • 检查io函数的返回值是否有错误

答案 1 :(得分:2)

嗯,一个问题是你使用 strcmp 。此函数需要一个ZERO-TERMINATED字符串( nes real_nes 都不是代码中以零结尾的字符串)。

另一个问题是 fread 。像这样使用它:

fread(nes, 1, 4, fp); // first size_t param is size and second is member count

更改您的代码:

int main()
{
        FILE *fp;
        fp = fopen("mario.nes", "rb");

        char nes[5];
        char real_nes[5] = "NES\x1a";
        fread(nes, 1, 4, fp);
        nes[4] = '\0';
        printf("A: %x\n", nes[3]);
        printf("B: %x\n", real_nes[3]);
        printf("C: %s\n", nes);
        printf("D: %s\n", real_nes);
        if (strcmp(nes, real_nes) != 0) {
            printf("not a match\n");
        }
        fclose(fp);
        return 0;
}

看看它是否有效。

答案 2 :(得分:1)

代码中的主要问题是:

char real_nes[4] = "NES\x1a";

这不是字符串,因为它不以nul-terminator char('\ 0')结尾。 对于'nes'来说,这是同样的问题。

只需声明它们:

char real_nes[] = "NES\x1a"; /* this is a string, ended by '\0' */
char nes[sizeof real_nes];

确保'\ 0'的位置正确。

现在您可以使用%s说明符或strcmp()。无论如何,我建议改为使用strncmp(),比如:

if(0 != strncmp(real_nes, nes, sizeof real_nes)) { /* some stuff */ }

HTH。

答案 3 :(得分:1)

不要在非零终止的字节数组上使用字符串函数。

问题是你有两个4字节数组,它们应该包含字符串“NES \ x1a”('\ 0'没有剩余空间,因为它已经是4个字节长),但%s格式和strcmp需要一个'\ 0'结束时终止知道字符串结束。这就是它无法正常工作的原因。

1:不要在此字节数组上使用%s格式的printf。 2:使用memcmp比较字节。

请改为尝试:

int i;

printf("Read bytes: 0x");
for(i = 0; i < sizeof(nes); i ++)
  printf("%02X", nes[i]);
printf("\n");

if (memcmp(nes, real_nes, sizeof(nes)) != 0) {
  printf("not a match\n");
}

答案 4 :(得分:1)

可能有点太晚了,但我的方法就是这样:

 // Read the 16 byte iNES header
    char header[16];
    fread( header, 16, 1, file );

    // Search for the "NES^Z" signature
    if( memcmp( header, "NES\x1A", 4 ) )
    {

正如Xeno所建议的,使用memcmp你不关心null终止符。毕竟,你并没有真正使用字符串,而是更像char数组,由于null终止符而不一样。因为除了调试之外你真的不需要打印签名,所以你根本不应该使用字符串函数。