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

发布于 2024-08-04 06:37:49 字数 777 浏览 6 评论 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 行似乎表明它应该是。

I'm reading in an NES ROM file, where the first four bytes are "\x4e\x45\x53\x1a", or NES\x1a. In my actual code, the given file can be arbitrary, so I want to check to make sure this header is here. However, I'm running into some trouble, which the following code demonstrates:

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

which returns:

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

where the question mark is \x1a.

I'm new to C, so it's possible I'm missing something subtle (or obvious) about why the two strings don't match, and why the question mark doesn't show when printing line D, to signify that \x1a is there at the end of the string, which line B seems to indicate it should be.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

月下客 2024-08-11 06:37:50

代码中的主要问题是:

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

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

The major problem in your code is:

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

This not a string, since it does not end with the nul-terminator char ('\0').
This is the same problem for 'nes'.

Just declare them like:

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

To be sure that there is enouth place for the '\0'.

Now you can use the %s specifier, or strcmp(). Anyway, I recommand the use of strncmp() instead, like in:

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

HTH.

诗化ㄋ丶相逢 2024-08-11 06:37:50

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

问题是您有两个 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");
}

Do not use string functions on not-zero-terminated byte arrays.

The problem is you have two 4 byte arrays which should contain the string "NES\x1a" (no space left for '\0' since it is already 4 bytes long), but the %s format and the strcmp need a '\0' termination at the end to know the strings end. That's why it doesn't work correctly.

1.: Do not use printf with %s format on this byte array.
2.: Use memcmp to compare the bytes.

Try this instead:

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");
}
凯凯我们等你回来 2024-08-11 06:37:50

也许有点太晚了,但我是这样做的:

 // 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 数组,由于 null 终止符,这并不相同。由于除了调试之外,您实际上并不需要打印签名,因此您根本不应该关心使用字符串函数。

A little too late maybe, but here's how I do it:

 // 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 ) )
    {

As Xeno proposed, with memcmp you don't care about null terminators. After all, you are not really using strings, but more like char arrays, which is not the same due to the null terminators. As you don't really need to print the signature other than for debugging, you shouldn't care using string functions at all.

酒儿 2024-08-11 06:37:49

一些评论和建议:

  • 以二进制模式打开文件 - 否则,在非 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 函数的返回值是否有错误

Some remarks and suggestions:

  • open the files in binary mode - otherwise, funny things may happen on non-POSIX systems (fixed)

    fp = fopen("mario.nes", "rb");
    
  • null-terminate your buffers if you want to print or compare them or use functions like strncmp() which accept the string's length as extra argument

    printf("C: %.4s\n", nes);
    printf("D: %.4s\n", real_nes);
    if (strncmp(nes, real_nes, 4) != 0) {
    
  • '\x1a' is the non-graphic substitute character ^Z

  • check the return values of io functions for errors
oО清风挽发oО 2024-08-11 06:37:49

好吧,一个问题是您对 strcmp 的使用。此函数需要一个以零结尾的字符串(nesreal_nes 都不是代码中以零结尾的字符串)。

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

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

然后看看它是否有效。

Well, one problem is your use of strcmp. This function expects a ZERO-TERMINATED string (neither nes nor real_nes are zero-terminated string in your code).

Another problem is fread. Use it like this:

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

Change your code like this:

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

And see if it works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文