Reputation:
Given a string of hex values i.e. e.g. "0011223344" so that's 0x00, 0x11 etc.
How do I add these values to a char array?
Equivalent to say:
char array[4] = { 0x00, 0x11 ... };
Upvotes: 11
Views: 72588
Reputation: 18259
Below are my hex2bin
and bin2hex
implementations.
These functions:
-1
means invalid hex string)static char h2b(char c) {
return '0'<=c && c<='9' ? c - '0' :
'A'<=c && c<='F' ? c - 'A' + 10 :
'a'<=c && c<='f' ? c - 'a' + 10 :
/* else */ -1;
}
int hex2bin(unsigned char* bin, unsigned int bin_len, const char* hex) {
for(unsigned int i=0; i<bin_len; i++) {
char b[2] = {h2b(hex[2*i+0]), h2b(hex[2*i+1])};
if(b[0]<0 || b[1]<0) return -1;
bin[i] = b[0]*16 + b[1];
}
return 0;
}
static char b2h(unsigned char b, int upper) {
return b<10 ? '0'+b : (upper?'A':'a')+b-10;
}
void bin2hex(char* hex, const unsigned char* bin, unsigned int bin_len, int upper) {
for(unsigned int i=0; i<bin_len; i++) {
hex[2*i+0] = b2h(bin[i]>>4, upper);
hex[2*i+1] = b2h(bin[i]&0x0F, upper);
}
}
Upvotes: 0
Reputation: 9837
The best way I know:
int hex2bin_by_zibri(char *source_str, char *dest_buffer)
{
char *line = source_str;
char *data = line;
int offset;
int read_byte;
int data_len = 0;
while (sscanf(data, " %02x%n", &read_byte, &offset) == 1) {
dest_buffer[data_len++] = read_byte;
data += offset;
}
return data_len;
}
The function returns the number of converted bytes saved in dest_buffer. The input string can contain spaces and mixed case letters.
"01 02 03 04 ab Cd eF garbage AB"
translates to dest_buffer containing 01 02 03 04 ab cd ef
and also "01020304abCdeFgarbageAB"
translates as before.
Parsing stops at the first "error" (non hex, non space).
Note: also this is a valid string:
"01 2 03 04 ab Cd eF garbage AB"
and produces:
01 02 03 04 ab cd ef
Upvotes: 1
Reputation: 1820
Let's say this is a little-endian ascii platform. Maybe the OP meant "array of char" rather than "string".. We work with pairs of char and bit masking.. note shiftyness of x16..
/* not my original work, on stacko somewhere ? */
for (i=0;i < 4;i++) {
char a = string[2 * i];
char b = string[2 * i + 1];
array[i] = (((encode(a) * 16) & 0xF0) + (encode(b) & 0x0F));
}
and function encode() is defined...
unsigned char encode(char x) { /* Function to encode a hex character */
/****************************************************************************
* these offsets should all be decimal ..x validated for hex.. *
****************************************************************************/
if (x >= '0' && x <= '9') /* 0-9 is offset by hex 30 */
return (x - 0x30);
else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */
return(x - 0x57);
else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */
return(x - 0x37);
}
This approach floats around elsewhere, it is not my original work, but it is old. Not liked by the purists because it is non-portable, but extension would be trivial.
Upvotes: 1
Reputation: 364
I was searching for the same thing and after reading a lot, finally created this function. Thought it might help, someone
// in = "63 09 58 81"
void hexatoascii(char *in, char* out, int len){
char buf[5000];
int i,j=0;
char * data[5000];
printf("\n size %d", strlen(in));
for (i = 0; i < strlen(in); i+=2)
{
data[j] = (char*)malloc(8);
if (in[i] == ' '){
i++;
}
else if(in[i + 1] == ' '){
i++;
}
printf("\n %c%c", in[i],in[i+1]);
sprintf(data[j], "%c%c", in[i], in[i+1]);
j++;
}
for (i = 0; i < j-1; i++){
int tmp;
printf("\n data %s", data[i] );
sscanf(data[i], "%2x", &tmp);
out[i] = tmp;
}
//printf("\n ascii value of hexa %s", out);
}
Upvotes: 1
Reputation: 40309
First, your question isn't very precise. Is the string a std::string
or a char
buffer? Set at compile-time?
Dynamic memory is almost certainly your answer.
char* arr = (char*)malloc(numberOfValues);
Then, you can walk through the input, and assign it to the array.
Upvotes: -4
Reputation: 698
{
char szVal[] = "268484927472";
char szOutput[30];
size_t nLen = strlen(szVal);
// Make sure it is even.
if ((nLen % 2) == 1)
{
printf("Error string must be even number of digits %s", szVal);
}
// Process each set of characters as a single character.
nLen >>= 1;
for (size_t idx = 0; idx < nLen; idx++)
{
char acTmp[3];
sscanf(szVal + (idx << 1), "%2s", acTmp);
szOutput[idx] = (char)strtol(acTmp, NULL, 16);
}
}
Upvotes: 0
Reputation: 1727
Give a best way:
Hex string to numeric value , i.e. str[] = "0011223344" to value 0x0011223344, use
value = strtoul(string, NULL, 16); // or strtoull()
done. if need remove beginning 0x00, see below.
though for LITTLE_ENDIAN platforms, plus: Hex value to char array, value 0x11223344 to char arr[N] = {0x00, 0x11, ...}
unsigned long *hex = (unsigned long*)arr;
*hex = htonl(value);
// you'd like to remove any beginning 0x00
char *zero = arr;
while (0x00 == *zero) { zero++; }
if (zero > arr) memmove(zero, arr, sizeof(arr) - (zero - arr));
done.
Notes: For converting long string to a 64 bits hex char arr on a 32-bit system, you should use unsigned long long instead of unsigned long, and htonl is not enough, so do it yourself as below because might there's no htonll, htonq or hton64 etc:
#if __KERNEL__
/* Linux Kernel space */
#if defined(__LITTLE_ENDIAN_BITFIELD)
#define hton64(x) __swab64(x)
#else
#define hton64(x) (x)
#endif
#elif defined(__GNUC__)
/* GNU, user space */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define hton64(x) __bswap_64(x)
#else
#define hton64(x) (x)
#endif
#elif
...
#endif
#define ntoh64(x) hton64(x)
see http://effocore.googlecode.com/svn/trunk/devel/effo/codebase/builtin/include/impl/sys/bswap.h
Upvotes: 0
Reputation: 753890
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).
Upvotes: 18
Reputation: 2466
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" )
Upvotes: 3
Reputation: 6297
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;
}
Upvotes: 3
Reputation: 41503
Fatalfloor...
There are a couple of ways to do this... first, you can use memcpy() to copy the exact representation into the char array.
You can use bit shifting and bit masking techniques as well. I'm guessing this is what you need to do as it sounds like a homework problem.
Lastly, you can use some fancy pointer indirection to copy the memory location you need.
All of these methods are detailed here:
Upvotes: 0