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

C 字符串比较中的十六进制文字问题,c,hex,fopen,strcmp,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];

我正在读取一个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;
}
其中问号为\x1a


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

一些评论和建议:

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

  • 如果要打印或比较缓冲区,或使用诸如
    strncmp()
    之类的函数(这些函数接受字符串的长度作为额外参数),请使用null终止缓冲区

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

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

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

另一个问题是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;
}
按如下方式更改代码:

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;
}

看看它是否有效。

代码中的主要问题是:

char real_nes[4] = "NES\x1a";
这不是字符串,因为它不以nul终止符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.

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

问题是您有两个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");
}
inti;
printf(“读取字节:0x”);
对于(i=0;i
可能有点晚了,但我是这样做的:

 // 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时,您不需要考虑空终止符。毕竟,您实际上并没有使用字符串,而是更像是字符数组,这与空终止符不同。由于除了调试之外,您实际上不需要打印签名,因此您根本不应该关心使用字符串函数。

strncmp()比较正确,因此我将其归因于一些奇怪之处,因为没有空终止符。谢谢。谢谢你对字符串的更全面的解释。即使在这个例子中,当执行
fread(nes,4,1,fp)时您没有将空终止符添加到nes[4],因此比较可能也不起作用<代码>网元[4]=0。Pablo,你为什么用
fread(nes,4,1,fp)
纠正
fread(nes,1,4,fp)
,它们不都读取4字节吗?(这是一个问题,不是挑战)是的,他们都在读4个字节。但您应该将每个成员的大小放在第一个参数上,并在第二个参数上读取count。因为他正在读取字符(1字节),所以第一个参数应该是1。这样,如果捕获fread的返回值(读取的元素数),您将获得正确的大小。