I want to convert two ASCII bytes to one hexadecimal byte.
eg.
0x30 0x43 => 0x0C , 0x34 0x46 => 0x4F ...
The ASCII bytes are a number between 0 and 9 or a letter between A and F (upper case only), so between 0x30 ... 0x39 and 0x41 ... 0x46
I know how "to construct" 0x4F with the numbers 0x34 and 0x46 : 0x4F = 0x34 * 0x10 + 0x46
So, in fact, i would to convert one ASCII byte in hexadecimal value.
For that, i can build and array to assign the hexadecimal value to the ASCII char :
0x30 => 0x00
0x31 => 0x01
...
0x46 => 0x0F
But, maybe it have a most « proper » solution.
The program will be run on an AVR µC and is compiled with avr-gcc, so scanf() / printf() solutions aren't suitable.
Have you got an idea ?
Thanks
i can't make sense of your examples, but if you want to convert a string containing hexadecimal ascii characters to its byte value (e.g. so the string "56" becomes the byte 0x56, you can use this (which assumes your system is using ASCII)
uint8_t*
hex_decode(const char *in, size_t len,uint8_t *out)
{
unsigned int i, t, hn, ln;
for (t = 0,i = 0; i < len; i+=2,++t) {
hn = in[i] > '9' ? in[i] - 'A' + 10 : in[i] - '0';
ln = in[i+1] > '9' ? in[i+1] - 'A' + 10 : in[i+1] - '0';
out[t] = (hn << 4 ) | ln;
}
return out;
}
You'd use it like e.g.
char x[]="1234";
uint8_t res[2];
hex_decode(x,strlen(x),res);
And res (which must be at least half the length of the in parameter) now contains the 2 bytes 0x12,0x34
Note also that this code needs the hexadecimal letters A-F to be capital, a-f won't do (and it doesn't do any error checking - so you'll have to pass it valid stuff).
You can use strtol(), which is part of avr-libc, or you can write just your specific case pretty easily:
unsigned char charToHexDigit(char c)
{
if (c >= 'A')
return c - 'A' + 10;
else
return c - '0';
}
unsigned char stringToByte(char c[2])
{
return charToHexDigit(c[0]) * 16 + charToHexDigit(c[1]);
}
The task:
Convert a string containing hexadecimal ascii characters to its byte values
so ascii "FF" becomes 0xFF and ascii "10" (x31x30x00) becomes 0x10
char asciiString[]="aaAA12fF";// input ascii hex string
char result[4]; // byte equivalent of the asciiString (the size should be at half of asciiString[])
// the final result should be:
result[0] = 0xAA;
result[1] = 0xAA;
result[2] = 0x12;
result[3] = 0xFF;
//1. Firt step: convert asciiString so it contains upper cases only:
// convert string to upper cases:
stringToUpperCases(asciiString);
use:
void stringToUpperCases(char *p)
{
for(int i=0; *(p+i) !='\0'; i++)
{
*(p+i) = (unsigned char) toupper( *(p+i) );
}
}
//2. Convert a string containing hexadecimal ascii characters to its byte values:
// convert string to bytes:
int nrOfBytes = stringToBytes(asciiString,result);
//use:
unsigned char charToHexDigit(char c)
{
if (c >= 'A')
return (c - 'A' + 10);
else
return (c - '0');
}
unsigned char ascii2HexToByte(char *ptr)
{
return charToHexDigit( *ptr )*16 + charToHexDigit( *(ptr+1) );
}
int stringToBytes(char *string, char *result)
{
int k=0;
int strLen = strlen(string);
for(int i = 0; i < strLen; i = i + 2)
{
result[k] = ascii2HexToByte( &string[i] );
k++;
}
return k; // number of bytes in the result array
}
//3. print result:
printNrOfBytes(nrOfBytes, result);
// use:
void printNrOfBytes(int nr, char *p)
{
for(int i= 0; i < nr; i++)
{
printf( "0x%02X ", (unsigned char)*(p+i) );
}
printf( "\n");
}
//4. The result should be:
0xAA 0xAA 0x12 0xFF
//5. This is the test program:
char asciiString[]="aaAA12fF"; // input ascii hex string
char result[4]; // result
// convert string to upper cases:
stringToUpperCases(asciiString);
// convert string to bytes
int nrOfBytes = stringToBytes(asciiString,result);
// print result:
printNrOfBytes(nrOfBytes, result);
// result:
// 0xAA 0xAA 0x12 0xFF
It's works, but could be much optimized !
inline uint8_t twoAsciiByteToByte(const std::string& s)
{
uint8_t r = 0;
if (s.length() == 4)
{
uint8_t a = asciiToByte(s[0]);
uint8_t b = asciiToByte(s[1]);
uint8_t c = asciiToByte(s[2]);
uint8_t d = asciiToByte(s[3]);
int h = (a * 10 + b);
int l = (c * 10 + d);
if (s[0] == '3')
h -= 30;
else if (s[0] == '4')
h -= 31;
if (s[2] == '3')
l -= 30;
else if (s[2] == '4')
l -= 31;
r = (h << 4) | l;
}
return r;
}
Here's a version that works with both upper and lower-case hex strings:
void hex_decode(const char *in, size_t len, uint8_t *out)
{
unsigned int i, hn, ln;
char hc, lc;
memset(out, 0, len);
for (i = 0; i < 2*len; i += 2) {
hc = in[i];
if ('a' <= hc && hc <= 'f') hc = toupper(hc);
lc = in[i+1];
if ('a' <= lc && lc <= 'f') lc = toupper(lc);
hn = hc > '9' ? hc - 'A' + 10 : hc - '0';
ln = lc > '9' ? lc - 'A' + 10 : lc - '0';
out[i >> 1] = (hn << 4 ) | ln;
}
}
Converting 2 hex chars to a byte is done in two steps:
Convert char a and b to their number (e.g. 'F' -> 0xF), which is done in two big if else branches, that check if the char is in the range '0' to '9', 'A' to 'F' or 'a' to 'f'.
In the 2nd step the two numbers are joined by shifting a (largest value is 0xF (0b0000_FFFF)) 4 to the left (a << 4 -> 0b1111_0000) and then apply the bitwise or operation on a and b ((a << 4) | b):
a: 0000_1111
b: 1111_0000
-> 1111_1111
#include <stdio.h>
#include <stdint.h>
#define u8 uint8_t
#define u32 uint32_t
u8 to_hex_digit(char a, char b) {
u8 result = 0;
if (a >= 0x30 && a <= 0x39) {
result = (a - 0x30) << 4;
} else if (a >= 0x41 && a <= 0x46) {
result = (a - 0x41 + 10) << 4;
} else if (a >= 0x61 && a <= 0x7A) {
result = (a - 0x61 + 10) << 4;
} else {
printf("invalid hex digit: '%c'\n", a);
}
if (b >= 0x30 && b <= 0x39) {
result |= b - 0x30;
} else if (b >= 0x41 && b <= 0x46) {
result |= b - 0x41 + 10;
} else if (b >= 0x61 && b <= 0x7A) {
result |= b - 0x61 + 10;
} else {
printf("invalid hex digit: '%c'\n", b);
}
return result;
}
u32 main() {
u8 result = to_hex_digit('F', 'F');
printf("0x%X (%d)\n", result, result);
return 0;
}
Related
I have a char[] that contains a value such as "0x1800785" but the function I want to give the value to requires an int, how can I convert this to an int? I have searched around but cannot find an answer. Thanks.
Have you tried strtol()?
strtol - convert string to a long integer
Example:
const char *hexstring = "abcdef0";
int number = (int)strtol(hexstring, NULL, 16);
In case the string representation of the number begins with a 0x prefix, one must should use 0 as base:
const char *hexstring = "0xabcdef0";
int number = (int)strtol(hexstring, NULL, 0);
(It's as well possible to specify an explicit base such as 16, but I wouldn't recommend introducing redundancy.)
Or if you want to have your own implementation, I wrote this quick function as an example:
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
uint32_t hex2int(char *hex) {
uint32_t val = 0;
while (*hex) {
// get current character then increment
uint8_t byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
Something like this could be useful:
char str[] = "0x1800785";
int num;
sscanf(str, "%x", &num);
printf("0x%x %i\n", num, num);
Read man sscanf
Assuming you mean it's a string, how about strtol?
Use strtol if you have libc available like the top answer suggests. However if you like custom stuff or are on a microcontroller without libc or so, you may want a slightly optimized version without complex branching.
#include <inttypes.h>
/**
* xtou64
* Take a hex string and convert it to a 64bit number (max 16 hex digits).
* The string must only contain digits and valid hex characters.
*/
uint64_t xtou64(const char *str)
{
uint64_t res = 0;
char c;
while ((c = *str++)) {
char v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8);
res = (res << 4) | (uint64_t) v;
}
return res;
}
The bit shifting magic boils down to: Just use the last 4 bits, but if it is an non digit, then also add 9.
One quick & dirty solution:
// makes a number from two ascii hexa characters
int ahex2int(char a, char b){
a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;
return (a << 4) + b;
}
You have to be sure your input is correct, no validation included (one could say it is C). Good thing it is quite compact, it works with both 'A' to 'F' and 'a' to 'f'.
The approach relies on the position of alphabet characters in the ASCII table, let's peek e.g. to Wikipedia (https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png). Long story short, the numbers are below the characters, so the numeric characters (0 to 9) are easily converted by subtracting the code for zero. The alphabetic characters (A to F) are read by zeroing other than last three bits (effectively making it work with either upper- or lowercase), subtracting one (because after the bit masking, the alphabet starts on position one) and adding ten (because A to F represent 10th to 15th value in hexadecimal code). Finally, we need to combine the two digits that form the lower and upper nibble of the encoded number.
Here we go with same approach (with minor variations):
#include <stdio.h>
// takes a null-terminated string of hexa characters and tries to
// convert it to numbers
long ahex2num(unsigned char *in){
unsigned char *pin = in; // lets use pointer to loop through the string
long out = 0; // here we accumulate the result
while(*pin != 0){
out <<= 4; // we have one more input character, so
// we shift the accumulated interim-result one order up
out += (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9; // add the new nibble
pin++; // go ahead
}
return out;
}
// main function will test our conversion fn
int main(void) {
unsigned char str[] = "1800785"; // no 0x prefix, please
long num;
num = ahex2num(str); // call the function
printf("Input: %s\n",str); // print input string
printf("Output: %x\n",num); // print the converted number back as hexa
printf("Check: %ld = %ld \n",num,0x1800785); // check the numeric values matches
return 0;
}
Try below block of code, its working for me.
char p[] = "0x820";
uint16_t intVal;
sscanf(p, "%x", &intVal);
printf("value x: %x - %d", intVal, intVal);
Output is:
value x: 820 - 2080
So, after a while of searching, and finding out that strtol is quite slow, I've coded my own function. It only works for uppercase on letters, but adding lowercase functionality ain't a problem.
int hexToInt(PCHAR _hex, int offset = 0, int size = 6)
{
int _result = 0;
DWORD _resultPtr = reinterpret_cast<DWORD>(&_result);
for(int i=0;i<size;i+=2)
{
int _multiplierFirstValue = 0, _addonSecondValue = 0;
char _firstChar = _hex[offset + i];
if(_firstChar >= 0x30 && _firstChar <= 0x39)
_multiplierFirstValue = _firstChar - 0x30;
else if(_firstChar >= 0x41 && _firstChar <= 0x46)
_multiplierFirstValue = 10 + (_firstChar - 0x41);
char _secndChar = _hex[offset + i + 1];
if(_secndChar >= 0x30 && _secndChar <= 0x39)
_addonSecondValue = _secndChar - 0x30;
else if(_secndChar >= 0x41 && _secndChar <= 0x46)
_addonSecondValue = 10 + (_secndChar - 0x41);
*(BYTE *)(_resultPtr + (size / 2) - (i / 2) - 1) = (BYTE)(_multiplierFirstValue * 16 + _addonSecondValue);
}
return _result;
}
Usage:
char *someHex = "#CCFF00FF";
int hexDevalue = hexToInt(someHex, 1, 8);
1 because the hex we want to convert starts at offset 1, and 8 because it's the hex length.
Speedtest (1.000.000 calls):
strtol ~ 0.4400s
hexToInt ~ 0.1100s
This is a function to directly convert hexadecimal containing char array to an integer which needs no extra library:
int hexadecimal2int(char *hdec) {
int finalval = 0;
while (*hdec) {
int onebyte = *hdec++;
if (onebyte >= '0' && onebyte <= '9'){onebyte = onebyte - '0';}
else if (onebyte >= 'a' && onebyte <='f') {onebyte = onebyte - 'a' + 10;}
else if (onebyte >= 'A' && onebyte <='F') {onebyte = onebyte - 'A' + 10;}
finalval = (finalval << 4) | (onebyte & 0xF);
}
finalval = finalval - 524288;
return finalval;
}
I have done a similar thing before and I think this might help you.
The following works for me:
int main(){
int co[8];
char ch[8];
printf("please enter the string:");
scanf("%s", ch);
for (int i=0; i<=7; i++) {
if ((ch[i]>='A') && (ch[i]<='F')) {
co[i] = (unsigned int) ch[i]-'A'+10;
} else if ((ch[i]>='0') && (ch[i]<='9')) {
co[i] = (unsigned int) ch[i]-'0'+0;
}
}
Here, I have only taken a string of 8 characters.
If you want you can add similar logic for 'a' to 'f' to give their equivalent hex values. Though, I haven't done that because I didn't need it.
I made a librairy to make Hexadecimal / Decimal conversion without the use of stdio.h. Very simple to use :
unsigned hexdec (const char *hex, const int s_hex);
Before the first conversion intialize the array used for conversion with :
void init_hexdec ();
Here the link on github : https://github.com/kevmuret/libhex/
I like #radhoo solution, very efficient on small systems. One can modify the solution for converting the hex to int32_t (hence, signed value).
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
int32_t hex2int(char *hex) {
uint32_t val = *hex > 56 ? 0xFFFFFFFF : 0;
while (*hex) {
// get current character then increment
uint8_t byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
Note the return value is int32_t while val is still uint32_t to not overflow.
The
uint32_t val = *hex > 56 ? 0xFFFFFFFF : 0;
is not protected against malformed string.
Here is a solution building upon "sairam singh"s solution. Where that answer is a one to one solution, this one combines two ASCII nibbles into one byte.
// Assumes input is null terminated string.
//
// IN OUT
// -------------------- --------------------
// Offset Hex ASCII Offset Hex
// 0 0x31 1 0 0x13
// 1 0x33 3
// 2 0x61 A 1 0xA0
// 3 0x30 0
// 4 0x00 NULL 2 NULL
int convert_ascii_hex_to_hex2(char *szBufOut, char *szBufIn) {
int i = 0; // input buffer index
int j = 0; // output buffer index
char a_byte;
// Two hex digits are combined into one byte
while (0 != szBufIn[i]) {
// zero result
szBufOut[j] = 0;
// First hex digit
if ((szBufIn[i]>='A') && (szBufIn[i]<='F')) {
a_byte = (unsigned int) szBufIn[i]-'A'+10;
} else if ((szBufIn[i]>='a') && (szBufIn[i]<='f')) {
a_byte = (unsigned int) szBufIn[i]-'a'+10;
} else if ((szBufIn[i]>='0') && (szBufIn[i]<='9')) {
a_byte = (unsigned int) szBufIn[i]-'0';
} else {
return -1; // error with first digit
}
szBufOut[j] = a_byte << 4;
// second hex digit
i++;
if ((szBufIn[i]>='A') && (szBufIn[i]<='F')) {
a_byte = (unsigned int) szBufIn[i]-'A'+10;
} else if ((szBufIn[i]>='a') && (szBufIn[i]<='f')) {
a_byte = (unsigned int) szBufIn[i]-'a'+10;
} else if ((szBufIn[i]>='0') && (szBufIn[i]<='9')) {
a_byte = (unsigned int) szBufIn[i]-'0';
} else {
return -2; // error with second digit
}
szBufOut[j] |= a_byte;
i++;
j++;
}
szBufOut[j] = 0;
return 0; // normal exit
}
I know this is really old but I think the solutions looked too complicated. Try this in VB:
Public Function HexToInt(sHEX as String) as long
Dim iLen as Integer
Dim i as Integer
Dim SumValue as Long
Dim iVal as long
Dim AscVal as long
iLen = Len(sHEX)
For i = 1 to Len(sHEX)
AscVal = Asc(UCase(Mid$(sHEX, i, 1)))
If AscVal >= 48 And AscVal <= 57 Then
iVal = AscVal - 48
ElseIf AscVal >= 65 And AscVal <= 70 Then
iVal = AscVal - 55
End If
SumValue = SumValue + iVal * 16 ^ (iLen- i)
Next i
HexToInt = SumValue
End Function
So I have an array of characters like the following {h,e,l,l,o,o}
so I need first to translate this to its bit representation, so what I would have is this
h = 01101000
e = 01100101
l = 01101100
l = 01101100
o = 01101111
o = 01101111
I need divide all of this bits in groups of five and save it to an array
so for example the union of all this characters would be
011010000110010101101100011011000110111101101111
And now I divide this in groups of five so
01101 00001 10010 10110 11000 11011 00011 01111 01101 111
and the last sequence should be completed with zeros so it would be 00111 instead. Note: Each group of 5 bits would be completed with a header in order to have 8 bits.
So I havent realized yet how to accomplish this, because I can extract the 5 bits of each character and get the representation of each character in binary as following
for (int i = 7; i >= 0; --i)
{
printf("%c", (c & (1 << i)) ? '1' : '0');
}
The problem is how to combine two characters so If I have two characters 00000001 and 11111110 when I divide in five groups I would have 5 bits of the first part of the character and for the second group I would have 3 bits from the last character and 2 from the second one. How can I make this combination and save all this groups in an array?
Assuming that a byte is made of 8 bits (ATTENTION: the C standard doesn't guarantee this), you have to loop over the string and play with bit operations to get it done:
>> n right shift to get rid of the n lowest bits
<< n to inject n times a 0 bit in the lowest position
& 0x1f to keep only the 5 lowest bits and reset the higer bits
| to merge high bits and low bits, when the overlapping bits are 0
This can be coded like this:
char s[]="helloo";
unsigned char last=0; // remaining bits from previous iteration in high output part
size_t j=5; // number of high input bits to keep in the low output part
unsigned char output=0;
for (char *p=s; *p; p++) { // iterate on the string
do {
output = ((*p >> (8-j)) | last) & 0x1f; // last high bits set followed by j bits shifted to lower part; only 5 bits are kept
printf ("%02x ",(unsigned)output);
j += 5; // take next block
last = (*p << (j%8)) & 0x1f; // keep the ignored bits for next iteration
} while (j<8); // loop if second block to be extracted from current byte
j -= 8;
}
if (j) // there are trailing bits to be output
printf("%02x\n",(unsigned)last);
online demo
The displayed result for your example will be (in hexadecimal): 0d 01 12 16 18 1b 03 0f 0d 1c, which corresponds exactly to each of the 5 bit groups that you have listed. Note that this code ads 0 right padding in the last block if it is not exactly 5 bits long (e.g. here the last 3 bits are padded to 11100 i.e. 0x1C instead of 111 which would be 0x0B)
You could easily adapt this code to store the output in a buffer instead of printing it. The only delicate thing would be to precalculate the size of the output which should be 8/5 times the original size, to be increased by 1 if it's not a multiple of 5 and again by 1 if you expect a terminator to be added.
Here is some code that should solve your problem:
#include <stdio.h>
#include <string.h>
int main(void)
{
char arr[6] = {'h', 'e', 'l', 'l', 'o', 'o'};
char charcode[9];
char binarr[121] = "";
char fives[24][5] = {{0}};
int i, j, n, numchars, grouping = 0, numgroups = 0;
/* Build binary string */
printf("\nCharacter encodings:\n");
for (j = 0; j < 6; j++) {
for (i = 0, n = 7; i < 8; i++, n--)
charcode[i] = (arr[j] & (01 << n)) ? '1' : '0';
charcode[8] = '\0';
printf("%c = %s\n", arr[j], charcode);
strcat(binarr, charcode);
}
/* Break binary string into groups of 5 characters */
numchars = strlen(binarr);
j = 0;
while (j < numchars) {
i = 0;
if ((numchars - j) < 5) { // add '0' padding
for (i = 0; i < (5 - (numchars - j)); i++)
fives[grouping][i] = '0';
}
while (i < 5) { // write binary digits
fives[grouping][i] = binarr[j];
++i;
++j;
}
++grouping;
++numgroups;
}
printf("\nConcatenated binary string:\n");
printf("%s\n", binarr);
printf("\nGroupings of five, with padded final grouping:\n");
for (grouping = 0; grouping <= numgroups; grouping++) {
for (i = 0; i < 5; i++)
printf("%c", fives[grouping][i]);
putchar(' ');
}
putchar('\n');
return 0;
}
When you run this as is, the output is:
Character encodings:
h = 01101000
e = 01100101
l = 01101100
l = 01101100
o = 01101111
o = 01101111
Concatenated binary string:
011010000110010101101100011011000110111101101111
Groupings of five, with padded final grouping:
01101 00001 10010 10110 11000 11011 00011 01111 01101 00111
#include <limits.h>
#include <stdio.h>
#define GROUP_SIZE 5
static int nextBit(void);
static int nextGroup(char *dest);
static char str[] = "helloo";
int main(void) {
char bits[GROUP_SIZE + 1];
int firstTime, nBits;
firstTime = 1;
while ((nBits = nextGroup(bits)) == GROUP_SIZE) {
if (!firstTime) {
(void) putchar(' ');
}
firstTime = 0;
(void) printf("%s", bits);
}
if (nBits > 0) {
if (!firstTime) {
(void) putchar(' ');
}
while (nBits++ < GROUP_SIZE) {
(void) putchar('0');
}
(void) printf("%s", bits);
}
(void) putchar('\n');
return 0;
}
static int nextBit(void) {
static int bitI = 0, charI = -1;
if (--bitI < 0) {
bitI = CHAR_BIT - 1;
if (str[++charI] == '\0') {
return -1;
}
}
return (str[charI] & (1 << bitI)) != 0 ? 1 : 0;
}
static int nextGroup(char *dest) {
int bit, i;
for (i = 0; i < GROUP_SIZE; ++i) {
bit = nextBit();
if (bit == -1) {
break;
}
dest[i] = '0' + bit;
}
dest[i] = '\0';
return i;
}
I'm looking for the least amount of code in C, in order to convert a char to int, where it flags -1 (or any error flag) if the char is not a valid hex digit.
here's what I came up with, is there a shorter way?
// input example
char input = 'f';
// conversion segment
int x = input - '0';
if (!((x >= 49 && x <= 54) || (x >= 0 && x <= 9))) x = -1;
if (x > 9) x -= 39;
// test print
printf("%d", x);
This code assumes ASCII and converts all 256 characters codes into 256 different codes, partially '0'-'9' 'A'-'F' map to 0,1,...15.
For additional tricks and simplification see the post
unsigned char ch = GetData(); // Fetch 1 byte of incoming data;
if (!(--ch & 64)) { // decrement, then if in the '0' to '9' area ...
ch = (ch + 7) & (~64); // move 0-9 next to A-Z codes
}
ch -= 54; // -= 'A' - 10 - 1
if (ch > 15) {
; // handle error
}
Try this function:
isxdigit(c);
I'm to stupid right now to solve this problem...
I get a BCD number (every digit is an own 4Bit representation)
For example, what I want:
Input: 202 (hex) == 514 (dec)
Output: BCD 0x415
Input: 0x202
Bit-representation: 0010 0000 0010 = 514
What have I tried:
unsigned int uiValue = 0x202;
unsigned int uiResult = 0;
unsigned int uiMultiplier = 1;
unsigned int uiDigit = 0;
// get the dec bcd value
while ( uiValue > 0 )
{
uiDigit= uiValue & 0x0F;
uiValue >>= 4;
uiResult += uiMultiplier * uiDigit;
uiMultiplier *= 10;
}
But I know that's very wrong this would be 202 in Bit representation and then split into 5 nibbles and then represented as decimal number again
I can solve the problem on paper but I just cant get it in a simple C-Code
You got it the wrong way round. Your code is converting from BCD to binary, just as your question's (original) title says. But the input and output values you provided are correct only if you convert from binary to BCD. In that case, try:
#include <stdio.h>
int main(void) {
int binaryInput = 0x202;
int bcdResult = 0;
int shift = 0;
printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );
while (binaryInput > 0) {
bcdResult |= (binaryInput % 10) << (shift++ << 2);
binaryInput /= 10;
}
printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
return 0;
}
Proof: http://ideone.com/R0reQh
Try the following.
unsigned long toPackedBcd (unsigned int val)
{
unsigned long bcdresult = 0; char i;
for (i = 0; val; i++)
{
((char*)&bcdresult)[i / 2] |= i & 1 ? (val % 10) << 4 : (val % 10) & 0xf;
val /= 10;
}
return bcdresult;
}
Also one may try the following variant (although maybe little inefficient)
/*
Copyright (c) 2016 enthusiasticgeek<enthusiasticgeek#gmail.com> Binary to Packed BCD
This code may be used (including commercial products) without warranties of any kind (use at your own risk)
as long as this copyright notice is retained.
Author, under no circumstances, shall not be responsible for any code crashes or bugs.
Exception to copyright code: 'reverse string function' which is taken from http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
Double Dabble Algorithm for unsigned int explanation
255(binary) - base 10 -> 597(packed BCD) - base 16
H| T| U| (Keep shifting left)
11111111
1 1111111
11 111111
111 11111
1010 11111 <-----added 3 in unit's place (7+3 = 10)
1 0101 1111
1 1000 1111 <-----added 3 in unit's place (5+3 = 8)
11 0001 111
110 0011 11
1001 0011 11 <-----added 3 in ten's place (6+3 = 9)
1 0010 0111 1
1 0010 1010 1 <-----added 3 in unit's place (7+3 = 10)
10 0101 0101 -> binary 597 but bcd 255
^ ^ ^
| | |
2 5 5
*/
#include <stdio.h>
#include <string.h>
//Function Prototypes
unsigned int binaryToPackedBCD (unsigned int binary);
char * printPackedBCD(unsigned int bcd, char * bcd_string);
// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str);
//Function Definitions
unsigned int binaryToPackedBCD (unsigned int binary) {
const unsigned int TOTAL_BITS = 32;
/*Place holder for bcd*/
unsigned int bcd = 0;
/*counters*/
unsigned int i,j = 0;
for (i=0; i<TOTAL_BITS; i++) {
/*
Identify the bit to append to LSB of 8 byte or 32 bit word -
First bitwise AND mask with 1.
Then shift to appropriate (nth shift) place.
Then shift the result back to the lsb position.
*/
unsigned int binary_bit_to_lsb = (1<<(TOTAL_BITS-1-i)&binary)>>(TOTAL_BITS-1-i);
/*shift by 1 place and append bit to lsb*/
bcd = ( bcd<<1 ) | binary_bit_to_lsb;
/*printf("=> %u\n",bcd);*/
/*Don't add 3 for last bit shift i.e. in this case 32nd bit*/
if( i >= TOTAL_BITS-1) {
break;
}
/*else continue*/
/* Now, check every nibble from LSB to MSB and if greater than or equal 5 - add 3 if so */
for (j=0; j<TOTAL_BITS; j+=4) {
unsigned int temp = (bcd & (0xf<<j))>>j;
if(temp >= 0x5) {
/*printf("[%u,%u], %u, bcd = %u\n",i,j, temp, bcd);*/
/*Now, add 3 at the appropriate nibble*/
bcd = bcd + (3<<j);
// printf("Now bcd = %u\n", bcd);
}
}
}
/*printf("The number is %u\n",bcd);*/
return bcd;
}
char * printPackedBCD(unsigned int bcd, char * bcd_string) {
const unsigned int TOTAL_BITS = 32;
printf("[LSB] =>\n");
/* Now, check every nibble from LSB to MSB and convert to char* */
for (unsigned int j=0; j<TOTAL_BITS; j+=4) {
//for (unsigned int j=TOTAL_BITS-1; j>=4; j-=4) {
unsigned int temp = (bcd & (0xf<<j))>>j;
if(temp==0){
bcd_string[j/4] = '0';
} else if(temp==1){
bcd_string[j/4] = '1';
} else if(temp==2){
bcd_string[j/4] = '2';
} else if(temp==3){
bcd_string[j/4] = '3';
} else if(temp==4){
bcd_string[j/4] = '4';
} else if(temp==5){
bcd_string[j/4] = '5';
} else if(temp==6){
bcd_string[j/4] = '6';
} else if(temp==7){
bcd_string[j/4] = '7';
} else if(temp==8){
bcd_string[j/4] = '8';
} else if(temp==9){
bcd_string[j/4] = '9';
} else {
bcd_string[j/4] = 'X';
}
printf ("[%u - nibble] => %c\n", j/4, bcd_string[j/4]);
}
printf("<= [MSB]\n");
reverse(bcd_string);
return bcd_string;
}
// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str)
{
if (str != 0 && *str != '\0') // Non-null pointer; non-empty string
{
char *end = str + strlen(str) - 1;
while (str < end)
{
char tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
int main(int argc, char * argv[])
{
unsigned int number = 255;
unsigned int bcd = binaryToPackedBCD(number);
char bcd_string[8];
printPackedBCD(bcd, bcd_string);
printf("Binary (Base 10) = %u => Packed BCD (Base 16) = %u\n OR \nPacked BCD String = %s\n", number, bcd, bcd_string);
return 0;
}
The real problem here is confusion of bases and units
The 202 should be HEX which equates to 514 decimal... and therefore the BCD calcs are correct
Binary code decimal will convert the decimal (514) into three nibble sized fields:
- 5 = 0101
- 1 = 0001
- 4 = 0100
The bigger problem was that you have the title the wrong way around, and you are converting Uint to BCD, whereas the title asked for BCD to Unint
My 2 cents, I needed similar for a RTC chip which used BCD to encode the time and date info. Came up with the following macros that worked fine for the requirement:
#define MACRO_BCD_TO_HEX(x) ((BYTE) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)))
#define MACRO_HEX_TO_BCD(x) ((BYTE) (((x / 10 ) << 4) | ((x % 10))))
A naive but simple solution:
char buffer[16];
sprintf(buffer, "%d", var);
sscanf(buffer, "%x", &var);
This is the solution that I developed and works great for embedded systems, like Microchip PIC microcontrollers:
#include <stdio.h>
void main(){
unsigned int output = 0;
unsigned int input;
signed char a;
//enter any number from 0 to 9999 here:
input = 1265;
for(a = 13; a >= 0; a--){
if((output & 0xF) >= 5)
output += 3;
if(((output & 0xF0) >> 4) >= 5)
output += (3 << 4);
if(((output & 0xF00) >> 8) >= 5)
output += (3 << 8);
output = (output << 1) | ((input >> a) & 1);
}
printf("Input decimal or binary: %d\nOutput BCD: %X\nOutput decimal: %u\n", input, output, output);
}
This is my version for a n byte conversion:
//----------------------------------------------
// This function converts n bytes Binary (up to 8, but can be any size)
// value to n bytes BCD value or more.
//----------------------------------------------
void bin2bcdn(void * val, unsigned int8 cnt)
{
unsigned int8 sz, y, buff[20]; // buff = malloc((cnt+1)*2);
if(cnt > 8) sz = 64; // 8x8
else sz = cnt * 8 ; // Size in bits of the data we shift
memset(&buff , 0, sizeof(buff)); // Clears buffer
memcpy(&buff, val, cnt); // Copy the data to buffer
while(sz && !(buff[cnt-1] & 0x80)) // Do not waste time with null bytes,
{ // so search for first significative bit
rotate_left(&buff, sizeof(buff)); // Rotate until we find some data
sz--; // Done this one
}
while(sz--) // Anyting left?
{
for( y = 0; y < cnt+2; y++) // Here we fix the nibbles
{
if(((buff[cnt+y] + 0x03) & 0x08) != 0) buff[cnt+y] += 0x03;
if(((buff[cnt+y] + 0x30) & 0x80) != 0) buff[cnt+y] += 0x30;
}
rotate_left(&buff, sizeof(buff)); // Rotate the stuff
}
memcpy(val, &buff[cnt], cnt); // Copy the buffer to the data
// free(buff); //in case used malloc
} // :D Done
long bin2BCD(long binary) { // double dabble: 8 decimal digits in 32 bits BCD
if (!binary) return 0;
long bit = 0x4000000; // 99999999 max binary
while (!(binary & bit)) bit >>= 1; // skip to MSB
long bcd = 0;
long carry = 0;
while (1) {
bcd <<= 1;
bcd += carry; // carry 6s to next BCD digits (10 + 6 = 0x10 = LSB of next BCD digit)
if (bit & binary) bcd |= 1;
if (!(bit >>= 1)) return bcd;
carry = ((bcd + 0x33333333) & 0x88888888) >> 1; // carrys: 8s -> 4s
carry += carry >> 1; // carrys 6s
}
}
Simple solution
#include <stdio.h>
int main(void) {
int binaryInput = 514 ; //0x202
int bcdResult = 0;
int digit = 0;
int i=1;
printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );
while (binaryInput > 0) {
digit = binaryInput %10; //pick digit
bcdResult = bcdResult+digit*i;
i=16*i;
binaryInput = binaryInput/ 10;
}
printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
return 0;
}
Binary: 0x202 (dec: 514)
BCD: 0x514 (dec: 1300)
You can also try the following:
In every iteration the remainder ( represented as a nibble ) is positioned in its corresponding place.
uint32_t bcd_converter(int num)
{
uint32_t temp=0;
int i=0;
while(num>0){
temp|=((num%10)<<i);
i+=4;
num/=10;
}
return temp;
}
I have a char[] that contains a value such as "0x1800785" but the function I want to give the value to requires an int, how can I convert this to an int? I have searched around but cannot find an answer. Thanks.
Have you tried strtol()?
strtol - convert string to a long integer
Example:
const char *hexstring = "abcdef0";
int number = (int)strtol(hexstring, NULL, 16);
In case the string representation of the number begins with a 0x prefix, one must should use 0 as base:
const char *hexstring = "0xabcdef0";
int number = (int)strtol(hexstring, NULL, 0);
(It's as well possible to specify an explicit base such as 16, but I wouldn't recommend introducing redundancy.)
Or if you want to have your own implementation, I wrote this quick function as an example:
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
uint32_t hex2int(char *hex) {
uint32_t val = 0;
while (*hex) {
// get current character then increment
uint8_t byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
Something like this could be useful:
char str[] = "0x1800785";
int num;
sscanf(str, "%x", &num);
printf("0x%x %i\n", num, num);
Read man sscanf
Assuming you mean it's a string, how about strtol?
Use strtol if you have libc available like the top answer suggests. However if you like custom stuff or are on a microcontroller without libc or so, you may want a slightly optimized version without complex branching.
#include <inttypes.h>
/**
* xtou64
* Take a hex string and convert it to a 64bit number (max 16 hex digits).
* The string must only contain digits and valid hex characters.
*/
uint64_t xtou64(const char *str)
{
uint64_t res = 0;
char c;
while ((c = *str++)) {
char v = (c & 0xF) + (c >> 6) | ((c >> 3) & 0x8);
res = (res << 4) | (uint64_t) v;
}
return res;
}
The bit shifting magic boils down to: Just use the last 4 bits, but if it is an non digit, then also add 9.
One quick & dirty solution:
// makes a number from two ascii hexa characters
int ahex2int(char a, char b){
a = (a <= '9') ? a - '0' : (a & 0x7) + 9;
b = (b <= '9') ? b - '0' : (b & 0x7) + 9;
return (a << 4) + b;
}
You have to be sure your input is correct, no validation included (one could say it is C). Good thing it is quite compact, it works with both 'A' to 'F' and 'a' to 'f'.
The approach relies on the position of alphabet characters in the ASCII table, let's peek e.g. to Wikipedia (https://en.wikipedia.org/wiki/ASCII#/media/File:USASCII_code_chart.png). Long story short, the numbers are below the characters, so the numeric characters (0 to 9) are easily converted by subtracting the code for zero. The alphabetic characters (A to F) are read by zeroing other than last three bits (effectively making it work with either upper- or lowercase), subtracting one (because after the bit masking, the alphabet starts on position one) and adding ten (because A to F represent 10th to 15th value in hexadecimal code). Finally, we need to combine the two digits that form the lower and upper nibble of the encoded number.
Here we go with same approach (with minor variations):
#include <stdio.h>
// takes a null-terminated string of hexa characters and tries to
// convert it to numbers
long ahex2num(unsigned char *in){
unsigned char *pin = in; // lets use pointer to loop through the string
long out = 0; // here we accumulate the result
while(*pin != 0){
out <<= 4; // we have one more input character, so
// we shift the accumulated interim-result one order up
out += (*pin < 'A') ? *pin & 0xF : (*pin & 0x7) + 9; // add the new nibble
pin++; // go ahead
}
return out;
}
// main function will test our conversion fn
int main(void) {
unsigned char str[] = "1800785"; // no 0x prefix, please
long num;
num = ahex2num(str); // call the function
printf("Input: %s\n",str); // print input string
printf("Output: %x\n",num); // print the converted number back as hexa
printf("Check: %ld = %ld \n",num,0x1800785); // check the numeric values matches
return 0;
}
Try below block of code, its working for me.
char p[] = "0x820";
uint16_t intVal;
sscanf(p, "%x", &intVal);
printf("value x: %x - %d", intVal, intVal);
Output is:
value x: 820 - 2080
So, after a while of searching, and finding out that strtol is quite slow, I've coded my own function. It only works for uppercase on letters, but adding lowercase functionality ain't a problem.
int hexToInt(PCHAR _hex, int offset = 0, int size = 6)
{
int _result = 0;
DWORD _resultPtr = reinterpret_cast<DWORD>(&_result);
for(int i=0;i<size;i+=2)
{
int _multiplierFirstValue = 0, _addonSecondValue = 0;
char _firstChar = _hex[offset + i];
if(_firstChar >= 0x30 && _firstChar <= 0x39)
_multiplierFirstValue = _firstChar - 0x30;
else if(_firstChar >= 0x41 && _firstChar <= 0x46)
_multiplierFirstValue = 10 + (_firstChar - 0x41);
char _secndChar = _hex[offset + i + 1];
if(_secndChar >= 0x30 && _secndChar <= 0x39)
_addonSecondValue = _secndChar - 0x30;
else if(_secndChar >= 0x41 && _secndChar <= 0x46)
_addonSecondValue = 10 + (_secndChar - 0x41);
*(BYTE *)(_resultPtr + (size / 2) - (i / 2) - 1) = (BYTE)(_multiplierFirstValue * 16 + _addonSecondValue);
}
return _result;
}
Usage:
char *someHex = "#CCFF00FF";
int hexDevalue = hexToInt(someHex, 1, 8);
1 because the hex we want to convert starts at offset 1, and 8 because it's the hex length.
Speedtest (1.000.000 calls):
strtol ~ 0.4400s
hexToInt ~ 0.1100s
This is a function to directly convert hexadecimal containing char array to an integer which needs no extra library:
int hexadecimal2int(char *hdec) {
int finalval = 0;
while (*hdec) {
int onebyte = *hdec++;
if (onebyte >= '0' && onebyte <= '9'){onebyte = onebyte - '0';}
else if (onebyte >= 'a' && onebyte <='f') {onebyte = onebyte - 'a' + 10;}
else if (onebyte >= 'A' && onebyte <='F') {onebyte = onebyte - 'A' + 10;}
finalval = (finalval << 4) | (onebyte & 0xF);
}
finalval = finalval - 524288;
return finalval;
}
I have done a similar thing before and I think this might help you.
The following works for me:
int main(){
int co[8];
char ch[8];
printf("please enter the string:");
scanf("%s", ch);
for (int i=0; i<=7; i++) {
if ((ch[i]>='A') && (ch[i]<='F')) {
co[i] = (unsigned int) ch[i]-'A'+10;
} else if ((ch[i]>='0') && (ch[i]<='9')) {
co[i] = (unsigned int) ch[i]-'0'+0;
}
}
Here, I have only taken a string of 8 characters.
If you want you can add similar logic for 'a' to 'f' to give their equivalent hex values. Though, I haven't done that because I didn't need it.
I made a librairy to make Hexadecimal / Decimal conversion without the use of stdio.h. Very simple to use :
unsigned hexdec (const char *hex, const int s_hex);
Before the first conversion intialize the array used for conversion with :
void init_hexdec ();
Here the link on github : https://github.com/kevmuret/libhex/
I like #radhoo solution, very efficient on small systems. One can modify the solution for converting the hex to int32_t (hence, signed value).
/**
* hex2int
* take a hex string and convert it to a 32bit number (max 8 hex digits)
*/
int32_t hex2int(char *hex) {
uint32_t val = *hex > 56 ? 0xFFFFFFFF : 0;
while (*hex) {
// get current character then increment
uint8_t byte = *hex++;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (byte >= '0' && byte <= '9') byte = byte - '0';
else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10;
else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10;
// shift 4 to make space for new digit, and add the 4 bits of the new digit
val = (val << 4) | (byte & 0xF);
}
return val;
}
Note the return value is int32_t while val is still uint32_t to not overflow.
The
uint32_t val = *hex > 56 ? 0xFFFFFFFF : 0;
is not protected against malformed string.
Here is a solution building upon "sairam singh"s solution. Where that answer is a one to one solution, this one combines two ASCII nibbles into one byte.
// Assumes input is null terminated string.
//
// IN OUT
// -------------------- --------------------
// Offset Hex ASCII Offset Hex
// 0 0x31 1 0 0x13
// 1 0x33 3
// 2 0x61 A 1 0xA0
// 3 0x30 0
// 4 0x00 NULL 2 NULL
int convert_ascii_hex_to_hex2(char *szBufOut, char *szBufIn) {
int i = 0; // input buffer index
int j = 0; // output buffer index
char a_byte;
// Two hex digits are combined into one byte
while (0 != szBufIn[i]) {
// zero result
szBufOut[j] = 0;
// First hex digit
if ((szBufIn[i]>='A') && (szBufIn[i]<='F')) {
a_byte = (unsigned int) szBufIn[i]-'A'+10;
} else if ((szBufIn[i]>='a') && (szBufIn[i]<='f')) {
a_byte = (unsigned int) szBufIn[i]-'a'+10;
} else if ((szBufIn[i]>='0') && (szBufIn[i]<='9')) {
a_byte = (unsigned int) szBufIn[i]-'0';
} else {
return -1; // error with first digit
}
szBufOut[j] = a_byte << 4;
// second hex digit
i++;
if ((szBufIn[i]>='A') && (szBufIn[i]<='F')) {
a_byte = (unsigned int) szBufIn[i]-'A'+10;
} else if ((szBufIn[i]>='a') && (szBufIn[i]<='f')) {
a_byte = (unsigned int) szBufIn[i]-'a'+10;
} else if ((szBufIn[i]>='0') && (szBufIn[i]<='9')) {
a_byte = (unsigned int) szBufIn[i]-'0';
} else {
return -2; // error with second digit
}
szBufOut[j] |= a_byte;
i++;
j++;
}
szBufOut[j] = 0;
return 0; // normal exit
}
I know this is really old but I think the solutions looked too complicated. Try this in VB:
Public Function HexToInt(sHEX as String) as long
Dim iLen as Integer
Dim i as Integer
Dim SumValue as Long
Dim iVal as long
Dim AscVal as long
iLen = Len(sHEX)
For i = 1 to Len(sHEX)
AscVal = Asc(UCase(Mid$(sHEX, i, 1)))
If AscVal >= 48 And AscVal <= 57 Then
iVal = AscVal - 48
ElseIf AscVal >= 65 And AscVal <= 70 Then
iVal = AscVal - 55
End If
SumValue = SumValue + iVal * 16 ^ (iLen- i)
Next i
HexToInt = SumValue
End Function