首页 文章

读取十六进制值并将其保存到unsigned char数组

提问于
浏览
0

我有一个包含以下格式的HEX值的文件

0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00

我想读取这些十六进制值并将其保存为相同格式的Unsigned char数组中的十六进制值

代码片段(十六进制是char数组,licensebin是unsigned char数组)

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

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

上面的代码没有正确读取值 .

4 回答

  • 1

    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 只能读取最多四个字符,因为它仍然是贪婪的 .

  • 4

    我尝试了下面的工作 . 当使用%x而不是unsigned char时,您可能需要将许可证定义为int:

    #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;
        }
    
    }
    
  • 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在匹配%x时所期望的类型 . )

    这旨在匹配输入中的文字“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;
    

    所有这些假设许可证是这样的:

    char *hex = "0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00";
    

    那就是你真的有一个'0'字符,'x'字符等 . 如果你的数据是二进制的,你需要一个完全不同的方法 .

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

    Input Files

    $ cat dat/hex3.txt
    0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00
    

    Use/Output

    $ ./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
    

    仔细看看,如果您有任何疑问,请告诉我 .

相关问题