0

我正在读取一个 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 行似乎表明它应该是。

4

5 回答 5

4

一些意见和建议:

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

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

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

  • 检查 io 函数的返回值是否有错误
于 2009-09-07T18:26:58.540 回答
2

好吧,一个问题是您对strcmp的使用。此函数需要一个以零结尾的字符串(在您的代码中,nesreal_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;
}

看看它是否有效。

于 2009-09-07T18:27:43.717 回答
1

您的代码中的主要问题是:

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

这不是字符串,因为它不以 nul 终止符字符 ('\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。

于 2009-09-07T18:36:20.453 回答
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");
}
于 2009-09-07T18:46:19.950 回答
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 你不需要关心空终止符。毕竟,您并没有真正使用字符串,而更像是 char 数组,由于空终止符,这并不相同。由于除了调试之外您实际上不需要打印签名,因此您根本不应该关心使用字符串函数。

于 2010-01-31T13:32:11.940 回答