0

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.

Matt Brailsford
  • 2,209
  • 3
  • 28
  • 40

4 Answers4

4

A simple implementation as follows:

int from_hex(uint16_t h)
{
    int d = 0;
    int power = 1;
    while (h)
    {
        // assert(h % 16 < 10)
        d += h % 16 * power;
        h /= 16;
        power *= 10;
    }
    return d;
}

And thanks to Minor Threat for the following:

int from_hex(uint16_t h)
{
    int d = 0;
    int power = 1;
    while (h)
    {
        // assert(h % 16 < 10)
        d += (h & 15) * power;
        h >>= 4;
        power *= 10;
    }
    return d;
}

I'm glad to know if something's wrong with my code

leyanpan
  • 433
  • 2
  • 9
  • Can anybody tell me why when they are down voting? I'm a new comer so I don't know how to answer properly – leyanpan Aug 26 '17 at 10:52
  • I'm very sorry in you consider my previous comments as an insult, I am just surprised that you have such high reputation but asks a relatively easy question – leyanpan Aug 26 '17 at 10:56
  • "easy" is relative. It's easy if you know. I just don't get why you need to include judging statements in your reply. Does nothing but makes the OP feel stupid for asking for help, which is what SO is for after all. – Matt Brailsford Aug 26 '17 at 14:48
  • I'm very sorry for my mistake, please forgive me for my ignorance – leyanpan Aug 26 '17 at 15:02
2

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
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
1

A simpler answer using streams and string conversions. Please note, this wont work in case of 0x0A, 0X0B, ... values.

uint16_t val = 0x80;
std::stringstream stream;
stream << std::hex << val;
std::string resultStr(stream.str());
// In case of 0xYY hex value be carefull that YY fits into an uint8_t, 
// otherwise  this will overflow
uint8_t result = static_cast<uint8_t>(std::stoi(resultStr));
Ervin Szilagyi
  • 14,274
  • 2
  • 25
  • 40
1

This should work for hex <= 0x99:

#include <iostream>

unsigned int foo(unsigned int hex)
{
    return  hex - (hex >> 4) * 6;
}

/* Test */
int main()
{
    unsigned int vals[] = {0x08, 0x09, 0x10, 0x11, 0x12, 0x80};

    for (int i = 0; i < sizeof(vals) / sizeof(vals[0]); i++)
        std::cout << foo(vals[i]) << std::endl;

    return 0;
}

Result:

8
9
10
11
12
80
sergej
  • 17,147
  • 6
  • 52
  • 89