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

时间:2016-02-05 07:03:43

标签: c

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

0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00

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

代码片段(十六进制是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 个答案:

答案 0 :(得分:4)

scanf function (and family)在读取数据时贪婪,这意味着"%x"格式会将 next 数字中的前导零读取为当前数字的最后零。

在您显示的示例中,它显示的第一个数字为0x020,而不是0x02

这可以通过告诉sscanf只读取四个字符来轻松解决:

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

在您添加关于licensebin[i]unsigned char的评论后,正确的格式应该是

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

前缀"hh"告诉sscanf该参数实际上是指向unsigned char的指针。 仍然需要告诉sscanf只能读取最多四个字符,因为它仍然是贪婪的。

答案 1 :(得分: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;

(感谢大家提醒我,匹配%x时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;

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

char *hex = "0x020x000x000x000x000x000x680x000x000x000x020x000x000x000x000x00";

那就是你真的有一个' 0'性格,' x'如果你的数据是二进制的,你需要一种完全不同的方法。

答案 2 :(得分:1)

我尝试了下面的工作。当使用%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;
    }

}

答案 3 :(得分:1)

处理十六进制字符串转换的最简单方法之一是使用strtoul来读取/转换base-16strtoul可以与指针一起使用,逐步执行输入字符串,提供每个找到的值的转换,然后只需将指针移动到下一个值的开头即可。根据您的输入,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

仔细看看,如果您有任何问题,请告诉我。