Since you say that the hex number never contains 'a', 'b', etc. this code should do the trick:
#include <iostream>
int main() {
uint16_t in = 0x4321;
int t = (1000 * ((in & 0xf000) / (16*16*16))) +
(100 * ((in & 0xf00) / (16*16))) +
(10 * ((in & 0xf0) / 16)) +
(1 * ((in & 0xf) / 1));
std::cout << t << std::endl;
return 0;
}
output
4321
Explanation
A 16 bit hex number in = 0xWZYX is calculated as
in = W*16^3 + Z*16^2 + Y*16^1 + X*16^0 (or just W*16^3 + Z*16^2 + Y*16^1 + X)
When doing
in & 0xf000 you get 0xW000
when doing
0xW000 / 16^3 you get 0x000W or just W
When doing
1000 * W you get W000 decimal
The pattern is then repeated for each digit.
An alternative implementation using shift
#include <iostream>
int main() {
uint16_t in = 0x9321;
int t = (1000 * ((in & 0xf000) >> 12)) +
(100 * ((in & 0xf00) >> 8)) +
(10 * ((in & 0xf0) >> 4)) +
(1 * ((in & 0xf) >> 0));
std::cout << t << std::endl;
return 0;
}
For a 16 bit unsigned integer it can be okay to write out the four lines. However, if you wanted a similar function for a larger unsigned int, it may be better to do a loop to keep the code more compact and maintainable.
64 bit solution using a loop
#include <iostream>
int64_t directHexToDec(uint64_t in)
{
int64_t res = 0;
uint64_t mask = 0xf;
uint64_t sh = 0;
uint64_t mul = 1;
for (int i=0; i<16; ++i)
{
res += mul * ((in & mask) >> sh);
mul *= 10;
mask <<= 4;
sh += 4;
}
return res;
}
int main() {
uint64_t in = 0x987654321;
int64_t t = directHexToDec(in);
std::cout << t << std::endl;
return 0;
}
output
987654321