1

how can I convert a hex string to a uint8_t array? My string is 02012B1530A6E3958A98530031902003876940000000000CDF9844173BE512AFFFFFFE11DBBA1F00079387800E13012E11FC017FFFFFFFFE39C10F40 and I want to convert it into this array:

uint8_t array_uint[] = {0x02, 0x01, 0x2B, 0x15, 0x30, 0xA6, 0xE3, 0x95, 0x8A, 0x98, 0x53, 0x00, 0x31, 0x90, 0x20, 0x03, 0x87, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xDF, 0x98, 0x44, 0x17, 0x3B, 0xE5, 0x12, 0xAF, 0xFF, 0xFF, 0xFE, 0x11, 0xDB, 0xBA, 0x1F, 0x00, 0x07, 0x93, 0x87, 0x80, 0x0E, 0x13, 0x01, 0x2E, 0x11, 0xFC, 0x01, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x39, 0xC1, 0x0F, 0x40};

Thank you for your help!

Gerhardh
  • 11,688
  • 4
  • 17
  • 39

3 Answers3

0

The first thing you need to learn is that decimal, hexadecimal or even octal are just how the binary numbers stored in the computer memory are presented. Once you store the bytes in your array, they aren't really hexadecimal anymore.

Now for how to solve your problem: You need to extract two characters at a time, then convert each character to the corresponding integer value, and use bit-shirt and bit-or to combine them into a single byte value.

Converting the digits 0 to 9 into their corresponding value is easy, since the C specification say that they must be encoded contiguously (i.e. '0' must come right before '1' and so on). That means you can use simple subtraction with '0' to get the numeric value ('0' - '0' == 0, '1' - '0' == 1 etc.).

The letters A to F are harder through, because there are many different possible encodings, including some that doesn't place letters contiguously. With that said, the most common encoding ASCII do is doing that, which means on most system you can use the same "trick" as for the decimal digits.

Then how to combine them, the first value needs to be shifted up (to the left) by four bits, and then bitwised OR'ed with the second value.

The result of that should be a single byte whose value is the same as the two hexadecimal digits from the string. Append this value to the array.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Probably my question wasn't clear at all, and I'm sorry for this. I only need to excract to characters at time from the string and put it into the uint8_t array. For example, my empty array is uint8_t myarray = {}, I excract "02" from the string and I add them to myarray, that will be myarray ={ 0x02 } –  Jul 24 '21 at 11:11
  • The standard C function strtol might be helpful, but you will then use a temporary zero-terminated string to which you copy two characters at a time. – Henrik Carlqvist Jul 24 '21 at 11:30
0

You can use sscanf() to convert 2 bytes at a time from the source string into the destination array:

#include <stdint.h>
#include <stdio.h>

size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
    size_t i;
    int value;
    for (i = 0; i < count && sscanf(src + i * 2, "%2x", &value) == 1; i++) {
        dest[i] = value;
    }
    return i;
}

Note however that this approach may be inefficient, with a quadratic time complexity, on architectures where the standard library computes the length of the source string for each call to sscanf(). Using an intermediary array solves this problem:

#include <stdint.h>
#include <stdio.h>

size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
    char buf[3];
    size_t i;
    int value;
    for (i = 0; i < count && *src; i++) {
        buf[0] = *src++;
        buf[1] = '\0';
        if (*src) {
            buf[1] = *src++;
            buf[2] = '\0';
        }
        if (sscanf(buf, "%x", &value) != 1)
            break;
        dest[i] = value;
    }
    return i;
}

Storing the conversion result directly into the dest array is easy:

#include <stdint.h>
#include <stdio.h>

size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
    char buf[3];
    size_t i;
    for (i = 0; i < count && *src; i++) {
        buf[0] = *src++;
        buf[1] = '\0';
        if (*src) {
            buf[1] = *src++;
            buf[2] = '\0';
        }
        if (sscanf(buf, "%hhx", &dest[i]) != 1)
            break;
    }
    return i;
}

Purists may argue that %hhx expects a pointer to an unsigned char instead of a uint8_t so the format should be "%"SCNx8 or "%2"SCNx8, defined in <inttypes.h>, but these alternatives are less readable and unnecessary as type uint8_t is always identical to type unsigned char on architectures where it is defined.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • thank you so much! do you know how to print the uint8_t array? if I do printf("%d", myarray[0]) it prints the decimal value of the first element of myarray. how can I print the exact element (0xFF, for example)? –  Jul 24 '21 at 12:30
  • @WonderWhy: decimal and hexadecimal are just representations of the *exact* value... Use `printf("0x%02X", myarray[0])` to get a hex representation with a `0x` prefix. Remove the `0x` to get the 2 hex bytes only. – chqrlie Jul 24 '21 at 13:15
0

With

char data[] = "02012B1530A6E3958A98530031902003876940000000000CDF9844173BE512AFFFFFFE11DBBA1F00079387800E13012E11FC017FFFFFFFFE39C10F40";
char *p = data;

first byte is

(hexdigit(p[0]) << 4) + hexdigit(p[1])

You can loop the above expression with

do {
    uint8_t value = (hexdigit(p[0]) << 4) + hexdigit(p[1]);
    p += 2;
} while (*p);

for all the values (make sure data has an even number of characters).

The function hexdigit() (implementation is left as an exercise) converts '0' to 0, '1' to 1, ..., 'a' to 10, 'A' to 10, ...

pmg
  • 106,608
  • 13
  • 126
  • 198