c: convert hex to same value decimal number
Mia Lopez
i have
UINT8 year = 0x15;and I want to get decimal value 15 in UINT8 decYear from year. How can I do it ? thankyou
background: I am ready day, month, year. I get value back 0x15, 0x10, 0x13 respectively for today. and I want to convert them to decimal values
126 Answers
The representation you are using is called Binary Coded Decimal and it's an old way of encoding values.
To get a "proper" decimal value you need to know how binary values work, and how to use the bitwise operators in C.
Lets say you have the BCD encoded value 0x15, this is binary 00010101. As you can see the 1 is stored in the high nibble and the 5 in the low. Getting them out by themselves is an easy bitwise-and operation:
int year = 0x15;
int high_nibble = year & 0xf0; // Gets the high nibble, i.e. `0x10`
int low_nibble = year & 0x0f; // Gets the low nibble, i.e. `0x05`Now you have two variables, one containing 0x10 and the other 0x05. The hexadecimal value 0x05 is the same as the decimal value 5, so nothing needs to be done with it. The other value needs some work to make it the decimal 10. For this we simply shift it down four bits (00010000 will become 00000001) doing
high_nibble >> 4and to "convert" it to decimal you multiply the value by 10 (1 * 10 == 10), and finally add the 5.
To put it all together into a single expression:
int decYear = ((year & 0xf0) >> 4) * 10 + (year & 0x0f); 1 In this specific case you can use this
UINT8 year = 0x15;
UINT8 yearD = year%16+ (year/16)*10;There's better solution using BCD encoding
UINT8 yearD = ((year>>4)&0x0f)*10+ (year&0x0f);Explanation:
Binary representation of 0x15 is 00010101. We have high nibble with 1 (0001) and low nibble 5(0101). So final result is higher nibble value *10 + value of lower nibble. To get high nibble value we do 4 shift right then bitwise AND with 0x0f, 4 right shift take high nibble value to lower nibble and bitwise and with 0x0f clear upper nibble, which is the real value of upper nibble. And to get lower nibble value we need to clear higher nibble value to do so we use year&0x0f.
Firstly: 0x15 is 21 (5 x 16 ^ 0) + ( 1 x 16 ^ 1 ), not 15.
Secondly, try:
UINT8 year = 0x15;
printf("%d",year);This is because, no value is saved as hex or decimal, but as binary, ultimately. The hex you used is but a representation for your system to be translated to binary, like 21 would be.
Making it output 15 would probably be very difficult and make the fact that you even entered it in hex superflous. Its like entering 21 and asking for us to contrive a way for the system to know you meant 15
If you get a value in hex as return from something, try converting it into a string and just cutting off the 0x part of it.
For example, if you get 0x15 as value, just read it in as string, and cut the 0x off with string operations.
A "hexadecimal value that contains no letters" is Binary Coded Decimal (BCD). You can convert BCD to decimal like this
#include <stdio.h>
#include <stdint.h>
uint8_t bcd2dec(uint8_t bcdval)
{ return (bcdval >> 4) * 10 + (bcdval & 0xF);
}
int main(int argc, char *argv[])
{ printf("Day %u\n", bcd2dec(0x13)); printf("Month %u\n", bcd2dec(0x10)); printf("Year %u\n", bcd2dec(0x15)); return 0;
}Program output:
Day 13
Month 10
Year 15 So if I understand correctly, you want to get 15 from 0x15.
You can use the following method:
char buffer[4];
UINT8 year = 0x15;
sprintf(buffer, "%x", year);if you print buffer, you get "15" as a string. You can then do:
UINT8 decYear = atoi(buffer); If 0x15 (in hexadecimal) does represent 15 (in decimal) then you are likely dealing with input in BCD format.
In such a case converting from BCD to decimal(1) is done by extracting each nible of the input and adding them properly.
Our input is a byte of 8 bits.
The 4 less significative bits (the lower nibble) represent the units, a number from 0 to 9. Values from A to F (hexadecimal) are never used.
The 4 most significative bits (the upper nibble) represent the tens. Also a number from 0 to 9.
If you extract them you get the decimal(1) value by the formula : tens*10 + units.
We can get the lower nibble with a binary mask : year & 0x0F
And the upper nibble with a right shift and the same binary mask : (year>>4) & 0x0F
The whole code is :
UINT8 year = 0x15;
assert ( ( (year>>4) & 0x0F ) < 10 ); // Ensure top nibble correctness
assert ( (year & 0x0F) < 10); // Ensure low nibble correcness
int yearBin = ( (year>>4) & 0x0F ) * 10 + (year&0x0F);
printf("%d\n", (int)yearBin); // Print yearBin in decimal : 15 will be printed
printf("%x\n", (int)yearBin); // Print yearBin in hexadecimal : // 0x15 will not be printed. 0xF will be printed.(1) Actually, we are not converting from BCD to decimal. We are converting from BCD to binary (most likely in 2-complement). It is the choice of conversion parameters in printf what makes it be printed in decimal.