1

I have a basic question regarding a c problem I'm having. My input char array would be something like:

'DABC95C1' 

and I want to make an uint8_t array out of it

0xDA 0xBC 0x95 0xC1

I have easily access to each char but I dont know how I can form 0xDA. Is there function in c or can i just cast it?

4
  • 3
    strtoull and then take bytes of the result. Commented May 28, 2018 at 14:10
  • What ways of printing it did you try with which of the format specifiers for printf? And what were the results? Commented May 28, 2018 at 14:10
  • 'char array' .... could You write snippets in more clear C with " Commented May 28, 2018 at 14:18
  • I might use repeated calls to sscanf with the format %2hhx. Commented May 28, 2018 at 14:28

3 Answers 3

4

Use the strtoull function to convert a string to a number in a given base. Then just shift out the desired bytes. Such as:

#include <stdio.h>
#include <stdlib.h>

int main(void) {

    unsigned long long res = strtoull("DABC95C1", NULL, 16);

    printf("%hhx, %hhx, %hhx, %hhx",
        (unsigned char)res,
        (unsigned char)((res >> 8)   &  0xFF),
        (unsigned char)((res >> 16)  &  0xFF),
        (unsigned char)((res >> 24)  &  0xFF)
    );

    return 0;
}

result:

c1, 95, bc, da

Demo

Notes:

As your requirement is to get an array of bytes, you might be tempted to do something like

uint8_t *arr = (uint8_t*)&res;

But here are two caveats in this:

1) I is a strict aliasing rule violation (you can somehow to work around it by replacing uint8_t with char)
2) The order of the returned bytes will be implementation specific (endianness dependent) and thus not portable. Also note that the result is unsigned long long, so you might get extra padding zeros as either the beginning of the array or in the end of it.

Sign up to request clarification or add additional context in comments.

7 Comments

So sad. I was about to upvote... But, now, I'm in doubt... (It's not 100 % perfect - you know.)
@Scheff The OP wanted an array as well, not just printing. The fishing pole, you know...
It is fairly safe to assume that uint8_t is a character type, because if there exists no character type of 8 bits for the given system, then uint8_t won't exist either. Which is only applicable to exotic, obsolete DSPs and the like, for which nobody needs code compatibility.
@Lundin Yes, and frankly speaking we are doing it at where I am working. But I guess it's more like to match the previously designed code, as I I was doing it from scratch I would try to do it as close to the standard as possible.
Very limited number of bytes. Up to 8. What if the string is more than 16byte long?
|
1

Any size string in the chosen order. Portable digit conversion and it optimizes very well on the ASCII systems. https://godbolt.org/g/Ycah1e

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

int CharToDigit(const char c);
void *StringToTable(const char *str, const void *buff, const int order)
{
    uint8_t *ptr = (uint8_t *)buff;
    size_t len;

    int incr = order ? 1 : -1;

    if(buff && str)
    {
        len = strlen(str);

        if(len &1) return NULL;

        ptr += order ? 0 : len / 2 - 1;

        while(*str)
        {
            int d1 = CharToDigit(*str++);
            int d2 = CharToDigit(*str++);

            if(d1 == -1 || d2 == -1) return NULL;           
            *ptr = d1 * 16 + d2;
            ptr += incr;
        }
    }
    return buff;
}

int main(void) {

    int index = 0;
    char *str = "78deAc8912fF0f3B";
    uint8_t buff[strlen(str) / 2];

    StringToTable(str, buff, 0);

    printf("String: %s\nResult: ", str);
    for(index = 0; index < strlen(str) / 2; index++ )
    {
        printf("[0x%02hhx]", buff[index] );
    }
    printf("\n");

    StringToTable(str, buff, 1);

    printf("String: %s\nResult: ", str);
    for(index = 0; index < strlen(str) / 2; index++ )
    {
        printf("[0x%02hhx]", buff[index] );
    }
    printf("\n");

    return 0;
}

int CharToDigit(const char c)
{
    switch(c)
    {
        case 'a':
        case 'A':
            return 10;
        case 'b':
        case 'B':
            return 11;
        case 'c':
        case 'C':
            return 12;
        case 'd':
        case 'D':
            return 13;
        case 'e':
        case 'E':
            return 14;
        case 'f':
        case 'F':
            return 15;
        case '0':
            return 0;
        case '1':
            return 1;
        case '2':
            return 2;
        case '3':
            return 3;
        case '4':
            return 4;
        case '5':
            return 5;
        case '6':
            return 6;
        case '7':
            return 7;
        case '8':
            return 8;
        case '9':
            return 9;
        default:
            return -1;
    }
}

Comments

0

You can conver a character to an int like so

static inline int char2int(char Ch)
{
    return(Ch>='0'&&Ch<='9')?(Ch-'0'):(Ch-'A'+10); 
    //assuming correct input with no lowercase letters
}

Two characters then with

static inline 
int chars2int(unsigned char const Chars[2])
{
    return (char2int(Chars[0])<<4)|(char2int(Chars[1]));
}

And several characters by converting each pair:

static inline int char2int(char Ch)
{
    return(Ch>='0'&&Ch<='9')?(Ch-'0'):(Ch-'A'+10);
}
static inline 
int chars2int(unsigned char const Chars[2])
{
    return (char2int(Chars[0])<<4)|(char2int(Chars[1]));
}
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main()
{
    char const inp[] = "DABC95C1";
    assert((sizeof(inp)-1)%2==0);
    unsigned i;
    unsigned char out[(sizeof(inp)-1)/2];
    for(i=0;i<sizeof(inp);i+=2){
        out[i/2]=chars2int((unsigned char*)inp+i);
    }
    for(i=0;i<sizeof(out);i++)
        printf("%2x\n", out[i]);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.