0

最初の 4 バイトが「\x4e\x45\x53\x1a」または NES\x1a である NES ROM ファイルを読み込んでいます。私の実際のコードでは、指定されたファイルは任意である可能性があるため、このヘッダーがここにあることを確認したいと思います。ただし、次のコードが示すように、いくつかの問題が発生しています。

#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 に慣れていないので、\x1a が文字列の最後にあり、B行がそうあるべきであることを示しているようです。

4

5 に答える 5

4

いくつかのコメントと提案:

  • バイナリ モードでファイルを開く - そうしないと、非 POSIX システムでおかしなことが起こる可能性があります (修正済み) 。

    fp = fopen("mario.nes", "rb");
    
  • バッファーを出力または比較する場合、またはstrncmp()文字列の長さを追加の引数として受け入れるような関数を使用する場合は、バッファーを null で終了します。

    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

さて、1 つの問題はstrcmpの使用です。この関数は ZERO-TERMINATED 文字列を想定しています (コード内の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

少し遅すぎるかもしれませんが、これが私がそれを行う方法です:

 // 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であるため同じではありません。デバッグ以外に署名を印刷する必要はないので、文字列関数を使用する必要はまったくありません。

于 2010-01-31T13:32:11.940 に答える
1

コードの主な問題は次のとおりです。

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。

于 2009-09-07T18:36:20.453 に答える
1

非ゼロ終了バイト配列で文字列関数を使用しないでください。

問題は、文字列 "NES\x1a" を含む 2 つの 4 バイト配列があることです (既に 4 バイト長であるため、'\0' のスペースは残っていません)。ただし、%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 に答える