简体   繁体   中英

Convert hex char[] to int[] in C 2 chars in 1 byte

I am trying to convert a char[] in hexadecimal format to int[] in hexadecimal.

Something like this:

hello --> 68656C6C6F --> [68, 65, 6C, 6C, 6F]

This is my code:

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

uint8_t* hex_decode(unsigned char *in, size_t len, uint8_t *out);

int main(void){
unsigned char  word_in[17], word_out[33];//17:16+1, 33:16*2+1
int i, len = 0;
uint8_t* out;


while(len != 16){
    printf("Set new word:");
    fgets( word_in, sizeof( word_in), stdin);
    len = strlen( word_in);
    if( word_in[len-1]=='\n')
        word_in[--len] = '\0';

    for(i = 0; i<len; i++){
        sprintf(word_out+i*2, "%02X",  word_in[i]);
    }
    if(len != 16){
        printf("Please, use a word of 16 chars long\n\n");
    }
}
printf("%s", word_in);
printf("\n");

hex_decode(word_out, sizeof(word_out), out);

return 0;
}

uint8_t* hex_decode(unsigned char *in, size_t len, uint8_t *out)
{
    unsigned int i, t, hn, ln;

    for (t = 0,i = 0; i < len; i+=2,++t) {

            hn = in[i] > '9' ? (in[i]|32) - 'a' + 10 : in[i] - '0';
            ln = in[i+1] > '9' ? (in[i+1]|32) - 'a' + 10 : in[i+1] - '0';

            out[t] = (hn << 4 ) | ln;
            printf("%s",out[t]);
    }
    return out;

}

But after printing the word, I got a segmentation fault.

That function works perfect in arduino so I think it should works fine at my computer... Where is the problem?

You get a segmentation fault because you are passing the pointer out before making any assignments to it. Either the hex_decode need to take uint8_t **out_ptr and assign it a dynamically allocated array, or the caller needs to provide an array sufficient to hold the output of the conversion.

The reason why it "works" on another platform is that it exhibits undefined behavior : in arduino, the arbitrary value placed in the uninitialized pointer out happens to point to an unused location in memory. Writing to that location does not trigger segmentation fault, creating an illusion of working code.

See @dasblinkenlight answer for seg fault. To decode 2 bytes:

My 50 C ent... (a short version)

char hex[3];
char * phex;
int result;
for(int i = 0; i < 256; i++)
{
    sprintf(hex, "%02X", i);
    phex = hex;
    result = ((*phex > 64 ? (*phex & 0x7) + 9 : *phex - 48) << 4) | (*(phex+1) > 64 ? (*(phex+1) & 0x7) + 9 : *(phex+1) - 48);
    if(result != i)
    {
        printf("err %s %02X\n", hex, result);
    }
}

Code above does no validation. This procedure returns -1 when input was invalid.

int h2i(char * ph)
{
    int result;
    if(*ph > 96 && *ph < 103) result = *ph - 87;
    else if(*ph > 64 && *ph < 71) result = *ph - 55;
    else if(*ph > 47 && *ph < 59) result = *ph - 48;
    else return -1;
    result <<= 4;
    ph++;
    if(*ph > 96 && *ph < 103) result |= *ph - 87;
    else if(*ph > 64 && *ph < 71) result |= *ph - 55;
    else if(*ph > 47 && *ph < 59) result |= *ph - 48;
    else return -1;
    return result;
}

But wait? A char can also be -1. Yes, after casting.

char * x = "FF";
char y;
int result;
result = h2i(x);
// if (result == -1) ...error...
y = (char)result;

The program looks complicated comparing what you want to do.

if you want to print the hexadecimal ascii code of a charachter, you can simply use

printf("%02X",'K'); // this will display the code ascii of 'K' in hexadecimal

If you want to print your word in code ascii in another char array. you can use sprintf() :

int main() {
        char word_in[17]="hello", word_out[33];
        char *pi = word_in, *po = word_out;
        word_out[0]=0;

        for (;*pi;po+=2,pi++)
           sprintf(po,"%02X",*pi);

        printf("%s\n", word_out);
}

A charachetr is saved in binary format in the memory. this binary format represent the code ascii of the charachter. And when you want to print its content:

  • when using "%d" : this will print the code ascii as integer
  • when using "%x" : this will print the code ascii as hexadecimal
  • when using "%c" : this will print the charachter

i will just share my own code for this:

it converts any 8 hexadecimal char string into a integer number from [-2147483648. 2147483647] input(argument) is 1 string(8+'\\0'), output(returns) is a long int, MODIFY AS NECESSARY

#define N 8

long int hex2dec(char* hex){        /*conversor HEX 2 DEC*/
    int i,j,n[N],l,neg;
    long int dec=0;

    for(i=0;i<N;i++){
        n[i]=0;
    }
    l=strlen(hex);

    neg=0;
    if(hex[0]>='8'){
        neg=1;
        for(i=0;i<N;i++){
            if(hex[i]=='0'){
                hex[i]='F';
                continue;
            }
            if(hex[i]=='1'){
                hex[i]='E';
                continue;
            }
            if(hex[i]=='2'){
                hex[i]='D';
                continue;
            }
            if(hex[i]=='3'){
                hex[i]='C';
                continue;
            }
            if(hex[i]=='4'){
                hex[i]='B';
                continue;
            }
            if(hex[i]=='5'){
                hex[i]='A';
                continue;
            }
            if(hex[i]=='6'){
                hex[i]='9';
                continue;
            }
            if(hex[i]=='7'){
                hex[i]='8';
                continue;
            }
            if(hex[i]=='8'){
                hex[i]='7';
                continue;
            }
            if(hex[i]=='9'){
                hex[i]='6';
                continue;
            }
            if(hex[i]=='A'){
                hex[i]='5';
                continue;
            }
            if(hex[i]=='B'){
                hex[i]='4';
                continue;
            }
            if(hex[i]=='C'){
                hex[i]='3';
                continue;
            }
            if(hex[i]=='D'){
                hex[i]='2';
                continue;
            }
            if(hex[i]=='E'){
                hex[i]='1';
                continue;
            }
            if(hex[i]=='F'){
                hex[i]='0';
                continue;
            }
        }
    }

    for(i=0;i<N;i++){
        switch(hex[i]){
        case '0':
            n[i]=hex[i]-48;  /* Ascii '0'=48 48-48=0*/
            break;
        case '1':
            n[i]=hex[i]-48;  /* Ascii '1'=49 49-48=1*/
            break;
        case '2':
            n[i]=hex[i]-48;
            break;
        case '3':
            n[i]=hex[i]-48;
            break;
        case '4':
            n[i]=hex[i]-48;
            break;
        case '5':
            n[i]=hex[i]-48;
            break;
        case '6':
            n[i]=hex[i]-48;
            break;
        case '7':
            n[i]=hex[i]-48;
            break;
        case '8':
            n[i]=hex[i]-48;
            break;
        case '9':
            n[i]=hex[i]-48;
            break;
        case 'A':
            n[i]=hex[i]-55;  /* Ascii 'A'=65 65-55=10*/
            break;
        case 'B':
            n[i]=hex[i]-55;  /* Ascii 'B'=66 66-55=11*/
            break;
        case 'C':
            n[i]=hex[i]-55;
            break;
        case 'D':
            n[i]=hex[i]-55;
            break;
        case 'E':
            n[i]=hex[i]-55;
            break;
        case 'F':
            n[i]=hex[i]-55;
            break;
        }
    }
    for(i=0,j=l;i<l;i++,j--){
        dec=dec+(n[j-1]*pow(16,i));
    }
    if(neg==1){
        dec=0-dec;
        dec=dec-1;
    }
    return dec;

}

change

uint8_t *out;//region is not ensured

to

uint8_t out[sizeof(word_out)/2];

change

hex_decode(word_out, sizeof(word_out), out);//sizeof(word_out) is 33, must to 32

to

hex_decode(word_out, strlen(word_out), out);//strlen(word_out) or len * 2 or sizeof(word_out) -1

change

printf("%s",out[t]);//out is not string

to

printf("%02X ",out[t]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM