Search code examples
c++hexconvertersbcd

How to convert Binary Coded Decimal to int in C++


Given a hex value of 0x80 (supplied as a uint16_t) in c++ how would I extract the digits into an int variable. I don't want to convert the hex to int, rather I want to extract the digits as an int, so for example, for 0x80 i want an int of 80, not 128, or for 0x55 I want 55 not 85, etc.

uint16_t hex = 0x80;
uint8_t val = ???; // Needs to be 80

Numbers with hex-only digits will never happen. I.e. input will only consist of decimal digits.
E.g. 0x08, 0x09, 0x10, 0x11, 0x12, etc.


Solution

  • 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