3

What basically i want to do is

For eg: 'a' hex equivalant is 0x61, can i split61 in to 6 and 1 and store them as '6' and '1' ?

A buffer is receiving data like this:

rx_dataframe.data[0] is H'00,'.'// H' is Hex equivalant and '' is ASCII value
rx_dataframe.data[0] is H'31,'1'
rx_dataframe.data[0] is H'32,'2'
rx_dataframe.data[0] is H'33,'3'

I need to to convert hex values 0x00,0x31,0x32,0x33 in to char value '0','0','3','1','3','2';'3','3' and to store them at the locations of tx_buff_data[];

I want my tx_buff_data look like this

tx_buff_data[0] have H'30,'0'
tx_buff_data[1] have H'30,'0'
tx_buff_data[2] have H'33,'3'
tx_buff_data[3] have H'31,'1'
tx_buff_data[4] have H'33,'3'
tx_buff_data[5] have H'32,'2'
tx_buff_data[6] have H'33,'3'
tx_buff_data[7] have H'33,'3'
User
  • 619
  • 1
  • 9
  • 24

7 Answers7

8

You can split each byte into two nibbles (4-bit quantities) using bitwise AND + shifts:

unsigned char lo = byte & 0x0f;
unsigned char hi = (byte >> 4) & 0x0f;

Then, you can convert each half into a hex character by an array lookup (since strings are just character arrays):

char loChar = "0123456789ABCDEF"[lo];
char hiChar = "0123456789ABCDEF"[hi];
Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • I've never seen `"0123456789ABCDEF"[lo];` before. Is that new? – Fiddling Bits Aug 15 '14 at 14:06
  • 1
    @FiddlingBits nope, it's the same thing as `const char *hex = "0123456789ABCDEF"; char loChar = hex[lo];`, just without the extra local variable. – Drew McGowen Aug 15 '14 at 14:09
  • @FiddlingBits: `"0123456789ABCDEF"` is an array and `[i]` is the bracket notation for accessing the element at offset `i` (zero based). What may come as a surprise is you can use `[]` with the arguments in the opposite order: `i["0123456789ABCDEF"]` also works and evaluates to `'6'` for `i==6`. – chqrlie Jul 18 '17 at 07:21
1

Here is a sample program that can be used as a template for your code

#include <stdio.h>

int main(void) 
{
    char in[] = { '\0', '1', '2', '3' };
    char out[2 * sizeof( in )];
    size_t  i;
    char *p;

    p = out;
    for ( i = 0; i < sizeof( in ) / sizeof( *in ); i++ )
    {
        *p = ( ( unsigned char )in[i] & 0xF0 ) >> 4;
        *p +=( *p < 10 ) ? '0' : 'A' - 10;
        ++p;
        *p = ( ( unsigned char )in[i] & 0x0F );
        *p +=( *p < 10 ) ? '0' : 'A' - 10;
        ++p;
    }

    for ( i = 0; i < sizeof( out ) / sizeof( *out ); i++ )
    {
        printf( "%c", out[i] );
    }

    puts( "" );

    return 0;
}

The output is

00313233
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

Using the definition of the ASCII characters leads to an extremely time- and code saving solution. The ASCII-table shows that

values  0... 9 <=> figures '0'...'9' <=> 0x30...0x39 in ASCII code;
values 10...15 <=> figures 'A'...'F' <=> 0x41...0x46 in ASCII code;
                   or      'a'...'f' <=> 0x61...0x66 in ASCII code;

Sometimes lower case letters are used for 'a' to 'f'.

So if the value of our nibble is below 10 (0000b to 1001b) the character representation would be 0x30 + n or, in c-syntax '0'+n.
If n is between 10 and 15 (1010b to 1111b) 0x41 + n - 10 or 'A'+n-10.
Using unsigned int 8bit instead of type char:

uint8_t nibble2char( uint8_t n ) {
  // make sure that n e {0x00,...,0x0F}
  if( n<10 ) return '0'+n;
  else       return 'A'+n-10;
}

or shorter:

uint8_t nibble2char( uint8_t n ) {
  // make sure that n e {0x00,...,0x0F}
  return n<10 ? '0'+n : 'A'+n-10;
}

or as a macro (thanks to chqrlie for the (n) ):

#define NIBBLE_TO_CHAR(n) ((n)<10 ? '0'+(n) : 'A'+(n)0)  // n <= 15 !

If lower case letters should be used replace 'A' by 'a'.

Converting a byte with 2 nibbles to a 2-byte 0-terminated string you could use:

void byte2str( uint8_t* s, uint8_t n ) {
  // s points to a string of at least 3 Bytes length !
  uint8_t hi = ( n >> 4 ) & 0x0F ;
  uint8_t lo =   n        & 0x0F ;
  s[0] = NIBBLE_TO_CHAR( hi );      // high byte
  s[1] = NIBBLE_TO_CHAR( lo );      // low byte
  s[2] = 0;
}

EDIT:
With correction of chqrlie to the macro, the function becomes more compact:

void byte2str( uint8_t* s, uint8_t n ) {
  // s points to a string of at least 3 Bytes length !
  s[0] = NIBBLE_TO_CHAR( ( n >> 4 ) & 0x0F );  // high byte
  s[1] = NIBBLE_TO_CHAR(   n        & 0x0F );  // low byte
  s[2] = 0;
}
peets
  • 393
  • 1
  • 4
  • 13
  • 1
    `#define NIBBLE_TO_CHAR(n) (n<10 ? '0'+n : 'A'+n-10)` -> `#define NIBBLE_TO_CHAR(n) ((n)<10 ? '0'+(n) : 'A'+(n)-10)` – chqrlie Jul 18 '17 at 07:22
0

to convert you can do:

    uint8_t lo = byte & 0x0F
    uint8_t hi = (byte >> 4) & 0x0F

   char loChar = "0123456789ABCDEF"[lo];
   char hiChar = "0123456789ABCDEF"[hi];
Gianluca Ghettini
  • 11,129
  • 19
  • 93
  • 159
0
for(int i = 0, j = 0; i < data_input_size; i++, j += 2)
{
    int value = rx_dataframe.data[i];
    char str[10]; // really only need 3 but extra space in case of bugs
    sprintf(str, "%02X", value);
    tx_buff_data[j] = str[0];
    tx_buff_data[j + 1] = str[1];
}
programmerjake
  • 1,794
  • 11
  • 15
  • `int value` should be `unsigned`. Also, this makes the assumption that `sprintf` is available on an embedded platform. – Drew McGowen Aug 15 '14 at 13:37
0

You can use sprintf to convert an integer value to a string, from the string you can then extract the individual chars.

#include <stdlib.h>

char *str;
sprintf(str, "%02x", 61)
char digitLow = str[0]; // '6'
char dightHigh = str[1]; // '1'
Gio
  • 3,242
  • 1
  • 25
  • 53
0

I propose you another variant, doing conversion of a fixed size input, and checking the size of the output:

void convert(char *output, int size_out, char *input, int size_in)
{
    static char hexdigit[] = "0123456789ABCDEF";
    while (size_in-- && size_out>2) {   // if not enough space, truncate 
        *output++ = hexdigit[(*input >> 4) & 0x0F];  // because char could be signed
        *output++ = hexdigit[*input & 0x0F];
        input++; 
        size_out -= 2;
    }
    *output++ = '\0';
}

As it is for a microcontroper, any overhead like sprintf() is avoided. You can call it like this:

   convert(tx_buff_data, sizeof(tx_buff_data), your_input_buffer, number_of_bytes); 
Christophe
  • 68,716
  • 7
  • 72
  • 138