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 - Convert hex string to string of bytes - Stack Overflow
How do you convert a byte array to a hexadecimal string 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;
/* allocate the buffer */
char * buffer = malloc((strlen(s) / 2) + 1);
char *h = s; /* this will walk through the hex string */
char *b = buffer; /* point inside the buffer */
/* offset into this string is the numeric value */
char xlate[] = "0123456789abcdef";
for ( ; *h; h += 2, ++b) /* go by twos through the hex string */
*b = ((strchr(xlate, *h) - xlate) * 16) /* multiply leading digit by 16 */
+ ((strchr(xlate, *(h+1)) - xlate));
Edited to add
In 80x86 assembly lanugage, the heart of strchr() is basically one instruction - it doesn't loop.
Also: this does no bounds checking, won't work with Unicode console input, and will crash if passed an invalid character.
Also: thanks to those who pointed out some serious typos.
Not that it'd make much difference, but I'd go with a multiplication over a division. Also it's worth splitting out the digit code, as you might want to port it to a platform where a-f are not adjacent in the character set (only joking!)
inline int digittoint(char d) {
return ((d) <= '9' ? (d) - '0' : (d) - 'a' + 10);
}
#define digittoint(d) ((d) <= '9' ? (d) - '0' : (d) - 'a' + 10)
size_t hexlength = strlen(s);
size_t binlength = hexlength / 2;
unsigned char * buffer = malloc(binlength);
long i = 0;
char a, b;
for (; i < binlength; ++i) {
a = s[2 * i + 0]; b = s[2 * i + 1];
buffer[i] = (digittoint(a) << 4) | digittoint(b);
}
I've fixed a bug in your digit-to-int implementation, and replaced the + with bitwise or on the grounds that it better expresses your intent.
You can then experiment to find the best implementation of digittoint - conditional arithmetic as above, strspn, or a lookup table.
Here's a possible branchless implementation that - bonus! - works on uppercase letters:
inline int digittoint(char d) {
return (d & 0x1f) + ((d >> 6) * 0x19) - 0x10;
}
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);
}
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!
This implementation uses the built-in strtol() function to handle the actual conversion from text to bytes, but will work for any even-length hex string.
std::vector<char> HexToBytes(const std::string& hex) {
std::vector<char> bytes;
for (unsigned int i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
char byte = (char) strtol(byteString.c_str(), NULL, 16);
bytes.push_back(byte);
}
return bytes;
}
This ought to work:
int char2int(char input)
{
if(input >= '0' && input <= '9')
return input - '0';
if(input >= 'A' && input <= 'F')
return input - 'A' + 10;
if(input >= 'a' && input <= 'f')
return input - 'a' + 10;
throw std::invalid_argument("Invalid input string");
}
// This function assumes src to be a zero terminated sanitized string with
// an even number of [0-9a-f] characters, and target to be sufficiently large
void hex2bin(const char* src, char* target)
{
while(*src && src[1])
{
*(target++) = char2int(*src)*16 + char2int(src[1]);
src += 2;
}
}
Depending on your specific platform there's probably also a standard implementation though.
There are indeed many methods (and they all work if done right).
Is it always a lenght of 8 ? That means it is 32-bit unsigned long number. The strtoul can convert it to a long. Use '16' for the base. If you need the seperate numbers, you can shift the unsigned long and convert to bytes or use a union.
It is also possible to do with a for statement can convert each character of the input to a value: forum.arduino.cc: convert HEX (ASCII) to a DEC int
[ADDED]
Thank you @goddland_16 for providing a full sketch. I could not stay behind and wrote a sketch with strtoul.
char *CardNumber = "B763AB23";
byte CardNumberByte[4];
void setup()
{
Serial.begin(9600);
Serial.println("With strtoul");
// Use 'nullptr' or 'NULL' for the second parameter.
unsigned long number = strtoul( CardNumber, nullptr, 16);
for(int i=3; i>=0; i--) // start with lowest byte of number
{
CardNumberByte[i] = number & 0xFF; // or: = byte( number);
number >>= 8; // get next byte into position
}
for(int i=0; i<4; i++)
{
Serial.print("0x");
Serial.println(CardNumberByte[i], HEX);
}
}
void loop()
{
}
Here is a simple solution to your question. I took each character, checked against its hexadecimal character and returned as a combination.
char CardNumber[] = "B763AB23";
byte CardNumberByte[4];
void setup() {
Serial.begin(9600);
}
void loop() {
for(char i = 0; i < 4; i++)
{
byte extract;
char a = CardNumber[2*i];
char b = CardNumber[2*i + 1];
extract = convertCharToHex(a)<<4 | convertCharToHex(b);
CardNumberByte[i] = extract;
Serial.println(CardNumberByte[i], HEX);
}
while(1);
}
char convertCharToHex(char ch)
{
char returnType;
switch(ch)
{
case '0':
returnType = 0;
break;
case '1' :
returnType = 1;
break;
case '2':
returnType = 2;
break;
case '3':
returnType = 3;
break;
case '4' :
returnType = 4;
break;
case '5':
returnType = 5;
break;
case '6':
returnType = 6;
break;
case '7':
returnType = 7;
break;
case '8':
returnType = 8;
break;
case '9':
returnType = 9;
break;
case 'A':
returnType = 10;
break;
case 'B':
returnType = 11;
break;
case 'C':
returnType = 12;
break;
case 'D':
returnType = 13;
break;
case 'E':
returnType = 14;
break;
case 'F' :
returnType = 15;
break;
default:
returnType = 0;
break;
}
return returnType;
}
Suppose your hex string is something like
>>> hex_string = "deadbeef"
Convert it to a bytearray (Python 3 and 2.7):
>>> bytearray.fromhex(hex_string)
bytearray(b'\xde\xad\xbe\xef')
Convert it to a bytes object (Python 3):
>>> bytes.fromhex(hex_string)
b'\xde\xad\xbe\xef'
Note that bytes is an immutable version of bytearray.
Convert it to a string (Python ≤ 2.7):
>>> hex_data = hex_string.decode("hex")
>>> hex_data
"\xde\xad\xbe\xef"
There is a built-in function in bytearray that does what you intend.
bytearray.fromhex("de ad be ef 00")
It returns a bytearray and it reads hex strings with or without space separator.