Hex to char array in C

Solution 1:

You can't fit 5 bytes worth of data into a 4 byte array; that leads to buffer overflows.

If you have the hex digits in a string, you can use sscanf() and a loop:

#include <stdio.h>
#include <ctype.h>

int main()
{
    const char *src = "0011223344";
    char buffer[5];
    char *dst = buffer;
    char *end = buffer + sizeof(buffer);
    unsigned int u;

    while (dst < end && sscanf(src, "%2x", &u) == 1)
    {
        *dst++ = u;
        src += 2;
    }

    for (dst = buffer; dst < end; dst++)
        printf("%d: %c (%d, 0x%02x)\n", dst - buffer,
               (isprint(*dst) ? *dst : '.'), *dst, *dst);

    return(0);
}

Note that printing the string starting with a zero-byte requires care; most operations terminate on the first null byte. Note that this code did not null-terminate the buffer; it is not clear whether null-termination is desirable, and there isn't enough space in the buffer I declared to add a terminal null (but that is readily fixed). There's a decent chance that if the code was packaged as a subroutine, it would need to return the length of the converted string (though you could also argue it is the length of the source string divided by two).

Solution 2:

I would do something like this;

// Convert from ascii hex representation to binary
// Examples;
//   "00" -> 0
//   "2a" -> 42
//   "ff" -> 255
// Case insensitive, 2 characters of input required, no error checking
int hex2bin( const char *s )
{
    int ret=0;
    int i;
    for( i=0; i<2; i++ )
    {
        char c = *s++;
        int n=0;
        if( '0'<=c && c<='9' )
            n = c-'0';
        else if( 'a'<=c && c<='f' )
            n = 10 + c-'a';
        else if( 'A'<=c && c<='F' )
            n = 10 + c-'A';
        ret = n + ret*16;
    }
    return ret;
}

int main()
{
    const char *in = "0011223344";
    char out[5];
    int i;

    // Hex to binary conversion loop. For example;
    // If in="0011223344" set out[] to {0x00,0x11,0x22,0x33,0x44}
    for( i=0; i<5; i++ )
    {
        out[i] = hex2bin( in );
        in += 2;
    }
    return 0;
}

Solution 3:

If the string is correct and no need to keep its content then i would do it this way:

#define hex(c) ((*(c)>='a')?*(c)-'a'+10:(*(c)>='A')?*(c)-'A'+10:*(c)-'0') 

void hex2char( char *to ){
  for(char *from=to; *from; from+=2) *to++=hex(from)*16+hex(from+1);
  *to=0;
}

EDIT 1: sorry, i forget to calculate with the letters A-F (a-f)

EDIT 2: i tried to write a more pedantic code:

#include <string.h> 

int xdigit( char digit ){
  int val;
       if( '0' <= digit && digit <= '9' ) val = digit -'0';
  else if( 'a' <= digit && digit <= 'f' ) val = digit -'a'+10;
  else if( 'A' <= digit && digit <= 'F' ) val = digit -'A'+10;
  else                                    val = -1;
  return val;
}

int xstr2str( char *buf, unsigned bufsize, const char *in ){
  if( !in ) return -1; // missing input string

  unsigned inlen=strlen(in);
  if( inlen%2 != 0 ) return -2; // hex string must even sized

  for( unsigned i=0; i<inlen; i++ )
    if( xdigit(in[i])<0 ) return -3; // bad character in hex string

  if( !buf || bufsize<inlen/2+1 ) return -4; // no buffer or too small

  for( unsigned i=0,j=0; i<inlen; i+=2,j++ )
    buf[j] = xdigit(in[i])*16 + xdigit(in[i+1]);

  buf[inlen/2] = '\0';
  return inlen/2+1;
}

Testing:

#include <stdio.h> 

char buf[100] = "test";

void test( char *buf, const char *s ){
   printf("%3i=xstr2str( \"%s\", 100, \"%s\" )\n", xstr2str( buf, 100, s ), buf, s );
}

int main(){
  test( buf,      (char*)0   );
  test( buf,      "123"      );
  test( buf,      "3x"       );
  test( (char*)0, ""         );
  test( buf,      ""         );
  test( buf,      "3C3e"     );
  test( buf,      "3c31323e" );

  strcpy( buf,    "616263"   ); test( buf, buf );
}

Result:

 -1=xstr2str( "test", 100, "(null)" )
 -2=xstr2str( "test", 100, "123" )
 -3=xstr2str( "test", 100, "3x" )
 -4=xstr2str( "(null)", 100, "" )
  1=xstr2str( "", 100, "" )
  3=xstr2str( "", 100, "3C3e" )
  5=xstr2str( "", 100, "3c31323e" )
  4=xstr2str( "abc", 100, "abc" )