2016-02-05 59 views
0

我有一個包含十六進制值的文件在以下格式從讀十六進制值,並將其保存爲unsigned char陣列

 
0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00 

我想讀這些十六進制值,並將其保存爲在同一個無符號字符數組的十六進制值的代碼格式

片段(十六進制被char數組,licensebin是無符號的字符數組)

fgets(hex, sizeof(hex), licenseFile); 

used = 0; 
while ((sscanf(hex+used, "%x", &licensebin[i]))==1) 
{ 
    printf("%x", licensebin[i]); 
    offset = 4; 
    used += offset; 
    i++; 
} 

以上代碼未正確讀取值。

+0

該文件是二進制的十六進制或字符? 'x020'不是一個十六進制字節值,那將是'x02'或'x20'。 –

+0

licensebin的類型是什麼? – Pooya

+0

@Pooya licensebin是無符號字符類型 –

回答

4

scanf function (and family)貪婪時讀取它的數據,這意味着"%x"格式將讀取從數前導零中的當前數目的最終爲零。

在您顯示的示例中,它讀取的第一個數字將是0x020而不是0x02

這可以很容易地通過告訴sscanf只需要解決讀四個大字:

sscanf(hex+used, "%4x", &licensebin[i]) 

後您添加的註釋約licensebin[i]作爲一個unsigned char,正確的格式實際上應該是

sscanf(hex+used, "%4hhx", &licensebin[i]) 

的前綴"hh"告訴sscanf該參數實際上是指向unsigned char的指針。你仍然需要告訴sscanf只讀最多四個字符,因爲它仍然貪婪。

+0

Downvoter謹慎解釋?我認爲所有的答案都是對的(約阿希姆是第一個)。 –

+0

'licensebin [i]'的註釋類型是'unsigned char'。 – BLUEPIXY

+0

感謝它的工作,我不知道sscanf的貪婪本質。 –

1

可能改變這樣的:

while ((sscanf(hex+used, "%x", &licensebin[i]))==1) 
{ 

要這樣:

unsigned int n; 
while ((sscanf(hex+used, "0x%2x", &n)==1) 
{  
    licensebin[i] = (unsigned char)n; 

(感謝大家提醒我匹配%×當scanf函數預計的類型。)

這是爲了匹配輸入中的字面值'0x',並將讀取的十六進制數字數限制爲2.

或者改變:

used = 0; 
while ((sscanf(hex+used, "%x", &licensebin[i]))==1) 

要:

used = 2; 
unsigned int n; 
while ((sscanf(hex+used, "%2x", &n)==1) 
{  
    licensebin[i] = (unsigned char)n; 

所有這些假設licensebin是一樣的東西:

char *hex = "0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00"; 

這是你從字面上有一個 '0' 字, 'X' 字符等等。如果你的數據是二進制的,你需要一個完全不同的方法。

+0

我想你的意思是'char * hex =「0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00」;' –

+0

@ PeterA.Schneider,Doh!對,我會解決它。謝謝。 – jimhark

1

我試了下面,它的工作。也許你需要定義許可證爲INT使用時%×代替unsigned char型:

#include <stdio.h> 

int main() { 

    int license[20]; 
    char* hex = "0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00"; 
    int used = 0; 
    int i = 0; 
    while((sscanf(hex+used,"%x",&license[i]))==1) 
    { 
     printf("%x",license[i]); 
     i++; 
     used += 4; 
    } 

} 
+0

不錯。您可以根據請求使用臨時int來保存scanf結果,將許可證更改爲unsigned char數組。如果您願意,請隨意從我的答案中複製該內容。 – jimhark

+0

@jimhark謝謝! – Pooya

1

一個處理十六進制字符串轉換的最簡單方法是使用strtoul其讀/轉換base-16能力。 strtoul可以和一個指針一起使用,通過輸入字符串逐步提供每個找到的值的轉換,然後將指針簡單地移動到下一個值的開頭。根據您的輸入,strchr用於查找每個'x',然後轉換後面的2個字符。

爲了幫助這個過程,您可以編寫一個簡單的函數來提供轉換的所有錯誤檢查和驗證。類似以下內容的效果很好:

/** string to unsigned long with error checking */ 
unsigned long xstrtoul (char *p, char **ep, int base) 
{ 
    errno = 0; 

    unsigned long tmp = strtoul (p, ep, base); 

    /* Check for various possible errors */ 
    if ((errno == ERANGE && (tmp == ULONG_MAX)) || 
     (errno != 0 && tmp == 0)) { 
     perror ("strtoul"); 
     exit (EXIT_FAILURE); 
    } 

    if (*ep == p) { 
     fprintf (stderr, "No digits were found\n"); 
     exit (EXIT_FAILURE); 
    } 

    return tmp; 
} 

您只需要最少的代碼即可將函數應用於數據文件中的所有行。例如:

#include <stdio.h> 
#include <stdlib.h> /* for strtol    */ 
#include <string.h> /* for strchr    */ 
#include <limits.h> /* for INT_MIN/INT_MAX  */ 
#include <errno.h> /* for errno    */ 

#define MAXL 256 

unsigned long xstrtoul (char *p, char **ep, int base); 

int main (int argc, char **argv) 
{ 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 
    char line[MAXL] = {0}; 
    unsigned values[MAXL] = {0}; 
    int base = argc > 2 ? atoi (argv[2]) : 16; 
    size_t i, idx = 0; 

    if (!fp) { /* validate file open */ 
     fprintf (stderr, "error: file open failen '%s'.\n", argv[1]); 
     return 1; 
    } 

    /* read each line in file (up to MAXL chars per-line) */ 
    while (fgets (line, MAXL, fp)) { 

     char *p = line; 
     char *ep = p; 
     char digits[3] = {0}; 
     errno = 0; 

     /* convert each string of digits into number */ 
     while (errno == 0) { 

      /* skip any non-digit characters */ 
      if (!(p = strchr (p, 'x'))) break; 
      strncpy (digits, ++p, 2); 
      digits[2] = 0; /* nul-terminate */ 

      /* convert string to number */ 
      values[idx++] = (unsigned)xstrtoul (digits, &ep, base); 

      if (errno || idx == MAXL) { /* check for error */ 
       fprintf (stderr, "warning: MAXL values reached.\n"); 
       break; 
      } 
      p += 2; 
     } 
    } 
    if (fp != stdin) fclose (fp); 

    /* print results */ 
    for (i = 0; i < idx; i++) 
     printf (" values[%2zu] : 0x%02x\n", i, values[i]); 

    return 0; 
} 

/** string to unsigned long with error checking */ 
unsigned long xstrtoul (char *p, char **ep, int base) 
{ 
    errno = 0; 

    unsigned long tmp = strtoul (p, ep, base); 

    /* Check for various possible errors */ 
    if ((errno == ERANGE && (tmp == ULONG_MAX)) || 
     (errno != 0 && tmp == 0)) { 
     perror ("strtoul"); 
     exit (EXIT_FAILURE); 
    } 

    if (*ep == p) { 
     fprintf (stderr, "No digits were found\n"); 
     exit (EXIT_FAILURE); 
    } 

    return tmp; 
} 

輸入文件

$ cat dat/hex3.txt 
0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00 

使用/輸出

$ ./bin/fgets_xstrtoul_simple dat/hex3.txt 
values[ 0] : 0x02 
values[ 1] : 0x00 
values[ 2] : 0x00 
values[ 3] : 0x00 
values[ 4] : 0x00 
values[ 5] : 0x00 
values[ 6] : 0x68 
values[ 7] : 0x00 
values[ 8] : 0x00 
values[ 9] : 0x00 
values[10] : 0x02 
values[11] : 0x00 
values[12] : 0x00 
values[13] : 0x00 
values[14] : 0x00 
values[15] : 0x00 

看一下它,並讓我知道如果您有任何問題。