2009-09-07 102 views
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行似乎表明它應該是。

回答

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' enouth地方。

現在您可以使用%s說明符或strcmp()。無論如何,我建議使用strncmp()代替,如下所示:

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

HTH。

+0

感謝您對字符串的更全面的解釋。 – v64 2009-09-07 18:42:03

+0

即使在這個例子中,當做'fread(nes,4,1,fp)'時,'你沒有向nes [4]添加空終止符,所以比較也可能不起作用。 'nes [4] = 0;'應該被添加。 – Petruza 2010-04-21 12:20:23

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函數的返回值的錯誤
+0

strncmp()比較正確,所以我會把它填充到一些奇怪的地方,因爲沒有空終止。謝謝。 – v64 2009-09-07 18:30:16

+0

哦,對,-b標誌,我忘了使用它。謝謝! – Petruza 2010-01-31 13:35:48

2

那麼,一個問題是你STRCMP的使用。此函數需要一個零終止字符串(在您的代碼中,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; 
} 

,看看它是否工作。

+0

Pablo,爲什麼你用'fread(nes,1,4,fp)'修正'fread(nes,4,1,fp)',是不是他們都讀完4個字節? (這是一個問題,而不是挑戰) – Petruza 2010-01-31 13:38:09

+0

是的,他們都讀取4個字節。但是你應該把每個成員的大小放在第一個參數上,並且讀第二個參數。由於他正在讀取字符(1字節),所以第一個參數應該是1.這樣,如果你抓住fread的返回值(讀取元素的數量),你會得到正確的大小。 – 2010-02-01 10:23:01

1

不要在非零終止的字節數組上使用字符串函數。

問題是你有兩個4字節的數組,它應該包含字符串「NES \ x1a」(因爲它已經有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"); 
} 
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)) 
    { 

作爲異種建議,與memcmp你不關心空終結。畢竟,你並沒有真正使用字符串,但更像是char數組,這與空終止符不同。由於您不需要打印除調試以外的簽名,因此您根本不應該在意使用字符串函數。

相關問題