As far as I know, there's no standard function to do so, but it's simple to achieve in the following manner:
#include <stdio.h>
int main(int argc, char **argv) {
const char hexstring[] = "DEadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
/* WARNING: no sanitization or error-checking whatsoever */
for (size_t count = 0; count < sizeof val/sizeof *val; count++) {
sscanf(pos, "%2hhx", &val[count]);
pos += 2;
}
printf("0x");
for(size_t count = 0; count < sizeof val/sizeof *val; count++)
printf("%02x", val[count]);
printf("\n");
return 0;
}
Edit
As Al pointed out, in case of an odd number of hex digits in the string, you have to make sure you prefix it with a starting 0. For example, the string "f00f5" will be evaluated as {0xf0, 0x0f, 0x05} erroneously by the above example, instead of the proper {0x0f, 0x00, 0xf5}.
As far as I know, there's no standard function to do so, but it's simple to achieve in the following manner:
#include <stdio.h>
int main(int argc, char **argv) {
const char hexstring[] = "DEadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
/* WARNING: no sanitization or error-checking whatsoever */
for (size_t count = 0; count < sizeof val/sizeof *val; count++) {
sscanf(pos, "%2hhx", &val[count]);
pos += 2;
}
printf("0x");
for(size_t count = 0; count < sizeof val/sizeof *val; count++)
printf("%02x", val[count]);
printf("\n");
return 0;
}
Edit
As Al pointed out, in case of an odd number of hex digits in the string, you have to make sure you prefix it with a starting 0. For example, the string "f00f5" will be evaluated as {0xf0, 0x0f, 0x05} erroneously by the above example, instead of the proper {0x0f, 0x00, 0xf5}.
I found this question by Googling for the same thing. I don't like the idea of calling sscanf() or strtol() since it feels like overkill. I wrote a quick function which does not validate that the text is indeed the hexadecimal presentation of a byte stream, but will handle odd number of hex digits:
uint8_t tallymarker_hextobin(const char * str, uint8_t * bytes, size_t blen)
{
uint8_t pos;
uint8_t idx0;
uint8_t idx1;
// mapping of ASCII characters to hex values
const uint8_t hashmap[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !"#$%&'
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~.
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ........
};
bzero(bytes, blen);
for (pos = 0; ((pos < (blen*2)) && (pos < strlen(str))); pos += 2)
{
idx0 = (uint8_t)str[pos+0];
idx1 = (uint8_t)str[pos+1];
bytes[pos/2] = (uint8_t)(hashmap[idx0] << 4) | hashmap[idx1];
};
return(0);
}
How to correctly convert a Hex String to Byte Array in C? - Stack Overflow
c - Converting ascii hex string to byte array - Stack Overflow
How to convert a hexadecimal to byte array in C - Stack Overflow
C help needed. (string to BYTE array)
You can use strtol() instead.
Simply replace this line:
sscanf(pos, "%2hhx", &val[count]);
with:
char buf[10];
sprintf(buf, "0x%c%c", pos[0], pos[1]);
val[count] = strtol(buf, NULL, 0);
UPDATE: You can avoid using sprintf() using this snippet instead:
char buf[5] = {"0", "x", pos[0], pos[1], 0};
val[count] = strtol(buf, NULL, 0);
You can either switch your compiler to C99 mode (the hh length modifier was standardised in C99), or you can use an unsigned int temporary variable:
unsigned int byteval;
if (sscanf(pos, "%2x", &byteval) != 1)
{
/* format error */
}
val[count] = byteval;
Sicne you talk about an embedded application I assume that you want to save the numbers as values and not as strings/characters. So if you just want to store your character data as numbers (for example in an integer), you can use sscanf.
This means you could do something like this:
char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
uint8 dest_val[3]; // We want to save 3 numbers
for(int i = 0; i<3; i++)
{
sscanf(&source_val[i*2],"%x%x",&dest_val[i]); // Everytime we read two chars --> %x%x
}
// Now dest_val contains 0x0A, 0x03 and 0xB7
However if you want to store it as a string (like in your example), you can't use unsigned char
since this type is also just 8-Bit long, which means it can only store one character. Displaying 'B3' in a single (unsigned) char does not work.
edit: Ok according to comments, the goal is to save the passed data as a numerical value. Unfortunately the compiler from the opener does not support sscanf which would be the easiest way to do so. Anyhow, since this is (in my opinion) the simplest approach, I will leave this part of the answer at it is and try to add a more custom approach in this edit.
Regarding the data type, it actually doesn't matter if you have uint8. Even though I would advise to use some kind of integer data type, you can also store your data into an unsigned char. The problem here is, that the data you get passed, is a character/letter, that you want to interpret as a numerical value. However, the internal storage of your character differs. You can check the ASCII Table, where you can check the internal values for every character.
For example:
char letter = 'A'; // Internally 0x41
char number = 0x61; // Internally 0x64 - represents the letter 'a'
As you can see there is also a differnce between upper an lower case.
If you do something like this:
int myVal = letter; //
myVal won't represent the value 0xA (decimal 10), it will have the value 0x41.
The fact you can't use sscanf means you need a custom function. So first of all we need a way to conver one letter into an integer:
int charToInt(char letter)
{
int myNumerical;
// First we want to check if its 0-9, A-F, or a-f) --> See ASCII Table
if(letter > 47 && letter < 58)
{
// 0-9
myNumerical = letter-48;
// The Letter "0" is in the ASCII table at position 48 -> meaning if we subtract 48 we get 0 and so on...
}
else if(letter > 64 && letter < 71)
{
// A-F
myNumerical = letter-55
// The Letter "A" (dec 10) is at Pos 65 --> 65-55 = 10 and so on..
}
else if(letter > 96 && letter < 103)
{
// a-f
myNumerical = letter-87
// The Letter "a" (dec 10) is at Pos 97--> 97-87 = 10 and so on...
}
else
{
// Not supported letter...
myNumerical = -1;
}
return myNumerical;
}
Now we have a way to convert every single character into a number. The other problem, is to always append two characters together, but this is rather easy:
int appendNumbers(int higherNibble, int lowerNibble)
{
int myNumber = higherNibble << 4;
myNumber |= lowerNibbler;
return myNumber;
// Example: higherNibble = 0x0A, lowerNibble = 0x03; -> myNumber 0 0xA3
// Of course you have to ensure that the parameters are not bigger than 0x0F
}
Now everything together would be something like this:
char source_val[] = {'0','A','0','3','B','7'} // Represents the numbers 0x0A, 0x03 and 0xB7
int dest_val[3]; // We want to save 3 numbers
int temp_low, temp_high;
for(int i = 0; i<3; i++)
{
temp_high = charToInt(source_val[i*2]);
temp_low = charToInt(source_val[i*2+1]);
dest_val[i] = appendNumbers(temp_high , temp_low);
}
I hope that I understood your problem right, and this helps..
If you have a "proper" array, like value as declared in the question, then you loop over the size of it to get each character. If you're on a system which uses the ASCII alphabet (which is most likely) then you can convert a hexadecimal digit in character form to a decimal value by subtracting '0' for digits (see the linked ASCII table to understand why), and subtracting 'A' or 'a' for letters (make sure no letters are higher than 'F' of course) and add ten.
When you have the value from the first hexadeximal digit, then convert the second hexadecimal digit the same way. Multiply the first value by 16 and add the second value. You now have single byte value corresponding to two hexadecimal digits in character form.
Time for some code examples:
/* Function which converts a hexadecimal digit character to its integer value */
int hex_to_val(const char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0'; /* Simple ASCII arithmetic */
else if (ch >= 'a' && ch <= 'f')
return 10 + ch - 'a'; /* Because hex-digit a is ten */
else if (ch >= 'A' && ch <= 'F')
return 10 + ch - 'A'; /* Because hex-digit A is ten */
else
return -1; /* Not a valid hexadecimal digit */
}
...
/* Source character array */
char value []={'0','2','0','c','0','3'};
/* Destination "byte" array */
char val[3];
/* `i < sizeof(value)` works because `sizeof(char)` is always 1 */
/* `i += 2` because there is two digits per value */
/* NOTE: This loop can only handle an array of even number of entries */
for (size_t i = 0, j = 0; i < sizeof(value); i += 2, ++j)
{
int digit1 = hex_to_val(value[i]); /* Get value of first digit */
int digit2 = hex_to_val(value[i + 1]); /* Get value of second digit */
if (digit1 == -1 || digit2 == -1)
continue; /* Not a valid hexadecimal digit */
/* The first digit is multiplied with the base */
/* Cast to the destination type */
val[j] = (char) (digit1 * 16 + digit2);
}
for (size_t i = 0; i < 3; ++i)
printf("Hex value %lu = %02x\n", i + 1, val[i]);
The output from the code above is
Hex value 1 = 02 Hex value 2 = 0c Hex value 3 = 03
A note about the ASCII arithmetic: The ASCII value for the character '0' is 48, and the ASCII value for the character '1' is 49. Therefore '1' - '0' will result in 1.
You can use strtoll function to do the conversion of individual bytes. The function takes a base parameter as its third argument, and reports the new position in the input, letting you decide between skipping the delimiter and reading more data, or finishing the loop:
char *ptr="ff:ff:fe:ff";
for (;;) {
int res = strtol(ptr, &ptr, 16);
printf("%x\n", res);
if (*ptr == ':') {
ptr++;
} else {
break;
}
}
Demo on ideone.
You probably could use sscanf() to read the values in.
#include <stdio.h>
int main() {
const char *input = "ff:ff:fe:ff";
unsigned int array[4];
int ret;
ret = sscanf(input, "%02x:%02x:%02x:%02x",
&array[0], &array[1], &array[2], &array[3]);
if (ret != 4) {
printf("Match failed.\n");
return -1;
}
printf("array = { %02x, %02x, %02x, %02x }\n",
array[0], array[1], array[2], array[3]);
return 0;
}
Output:
array = { ff, ff, fe, ff }
Hello:
Would someone please point me to the solution for this? ( I am a C newbie )
I am running a C program with an Input argument .
This argument (argv[1]) is a string containing "1112131415e0",
I need to have this string stored in a BYTE array (container1) such that is the same as if I wrote :
BYTE container1[] = { 0x11, 0x12, 0x13, 0x14,0x14,0xe0}
I don't want to convert 11 to hex.. I just want to add the 0x and have it stored.
Thanks a lot!
Hi everyone, I'm making an Arduino project in which i read a string from a software serial port, and then i would like to convert this string, reading the characters two at a time, into an HEX vector. How could i do it?
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);
For a more generic way:
int i;
for (i = 0; i < x; i++)
{
if (i > 0) printf(":");
printf("%02X", buf[i]);
}
printf("\n");
To concatenate to a string, there are a few ways you can do this. I'd probably keep a pointer to the end of the string and use sprintf. You should also keep track of the size of the array to make sure it doesn't get larger than the space allocated:
int i;
char* buf2 = stringbuf;
char* endofbuf = stringbuf + sizeof(stringbuf);
for (i = 0; i < x; i++)
{
/* i use 5 here since we are going to add at most
3 chars, need a space for the end '\n' and need
a null terminator */
if (buf2 + 5 < endofbuf)
{
if (i > 0)
{
buf2 += sprintf(buf2, ":");
}
buf2 += sprintf(buf2, "%02X", buf[i]);
}
}
buf2 += sprintf(buf2, "\n");
For completude, you can also easily do it without calling any heavy library function (no snprintf, no strcat, not even memcpy). It can be useful, say if you are programming some microcontroller or OS kernel where libc is not available.
Nothing really fancy you can find similar code around if you google for it. Really it's not much more complicated than calling snprintf and much faster.
#include <stdio.h>
int main(){
unsigned char buf[] = {0, 1, 10, 11};
/* target buffer should be large enough */
char str[12];
unsigned char * pin = buf;
const char * hex = "0123456789ABCDEF";
char * pout = str;
int i = 0;
for(; i < sizeof(buf)-1; ++i){
*pout++ = hex[(*pin>>4)&0xF];
*pout++ = hex[(*pin++)&0xF];
*pout++ = ':';
}
*pout++ = hex[(*pin>>4)&0xF];
*pout++ = hex[(*pin)&0xF];
*pout = 0;
printf("%s\n", str);
}
Here is another slightly shorter version. It merely avoid intermediate index variable i and duplicating laste case code (but the terminating character is written two times).
#include <stdio.h>
int main(){
unsigned char buf[] = {0, 1, 10, 11};
/* target buffer should be large enough */
char str[12];
unsigned char * pin = buf;
const char * hex = "0123456789ABCDEF";
char * pout = str;
for(; pin < buf+sizeof(buf); pout+=3, pin++){
pout[0] = hex[(*pin>>4) & 0xF];
pout[1] = hex[ *pin & 0xF];
pout[2] = ':';
}
pout[-1] = 0;
printf("%s\n", str);
}
Below is yet another version to answer to a comment saying I used a "trick" to know the size of the input buffer. Actually it's not a trick but a necessary input knowledge (you need to know the size of the data that you are converting). I made this clearer by extracting the conversion code to a separate function. I also added boundary check code for target buffer, which is not really necessary if we know what we are doing.
#include <stdio.h>
void tohex(unsigned char * in, size_t insz, char * out, size_t outsz)
{
unsigned char * pin = in;
const char * hex = "0123456789ABCDEF";
char * pout = out;
for(; pin < in+insz; pout +=3, pin++){
pout[0] = hex[(*pin>>4) & 0xF];
pout[1] = hex[ *pin & 0xF];
pout[2] = ':';
if (pout + 3 - out > outsz){
/* Better to truncate output string than overflow buffer */
/* it would be still better to either return a status */
/* or ensure the target buffer is large enough and it never happen */
break;
}
}
pout[-1] = 0;
}
int main(){
enum {insz = 4, outsz = 3*insz};
unsigned char buf[] = {0, 1, 10, 11};
char str[outsz];
tohex(buf, insz, str, outsz);
printf("%s\n", str);
}