2

Given an unsigned integer, I need to end up with a 6-digits long hexadecimal value.

  • 81892 (hex: 13FE4), should become 13FE40 or 013FE4
  • 3285446057 (hex: C3D3EDA9), should become C3D3ED or D3EDA9

Since the project I'm contributing to uses Qt, I solve the problem this way:

unsigned int hex = qHash(name);
QString hexStr = (QString::number(hex, 16) + "000000").left(6);
bool ok;
unsigned int hexPat = hexStr.toUInt(&ok, 16);

This pads the hex number string on the right and then trims it after the sixth character from the left. To do the opposite, I would simply replace the second line:

QString hexStr = ("000000" + QString::number(hex, 16)).right(6);

The value will be used for RGB values, which is why I need six hex digits (three values between 0 and 255).

Is there a more efficient way to achieve either (or both) of these results without converting to string and then back?

Community
  • 1
  • 1
qubodup
  • 8,687
  • 5
  • 37
  • 45

1 Answers1

2

The actual requirement for your problem is given an unsigned integer, you need to extract three bytes.

There really isn't any need to convert to a string to extract them, it can be more effectively performed using bit operations.

To extract any byte from the integer, right-shift (>>) the corresponding number of bits (0, 8, 16 or 24), and AND the result with a mask that takes only the rightmost byte (0xFF, which is really 0x000000FF).

e.g. take the three least significant bytes:

uint c = hash(...);
BYTE r = (BYTE)((c >> 16) & 0xFF);
BYTE g = (BYTE)((c >> 8) & 0xFF);
BYTE b = (BYTE)(c & 0xFF);

or three most significant bytes:

uint c = hash(...);
BYTE r = (BYTE)((c >> 24) & 0xFF);
BYTE g = (BYTE)((c >> 16) & 0xFF);
BYTE b = (BYTE)((c >> 8) & 0xFF);
Rotem
  • 21,452
  • 6
  • 62
  • 109
  • BYTE as in http://stackoverflow.com/a/20025042/188159 ? Could I use int or unsigned int instead, as to avoid including anything and defining new types? (I feel I should do that, as I hardly know the project I contribute to and probably don't know yet what implications such additions might have on performance and other sections of code) PS: Thanks for re-stating my question, it's very helpful to understanding the process. – qubodup Nov 01 '15 at 09:49
  • Sorry, I'm used to Windows, I forget it's not part of the language. `BYTE` is defined as `unsigned char`. It may probably work just as well, though less specific, with an int or uint, depends on where the values need to go later. – Rotem Nov 01 '15 at 10:02
  • Thanks for clarifying. I'm especially interested in using the most significant bytes (left part) but unfortunately your code doesn't seem to handle short hashes. 1cf9e becomes 00,01,cf rather than 1c,f9,e0 and ef becomes 00,00,00 rather than ef,00,00 http://rextester.com/PGV72502 (also happens when using unsigned char rather than unsigned int) - I'm also worried this might be inconsistent between 32bit/64bit operating systems? – qubodup Nov 02 '15 at 05:03
  • @qubodup It sounds like you're interested in the least significant bytes. – Rotem Nov 02 '15 at 05:32
  • My inexperience with bits/bytes makes me say unclear things I think. I am interested in the three leftmost bytes, the leftmost of which is not equal to zero. – qubodup Nov 02 '15 at 12:27
  • leftmost is endianness dependent. If you have the number `0x12345678` you want to get `0x123456`, but if you have `0x00345678`, you want to get `0x345678`? You could check if the most significant byte is `0`, and then decide which 3 bytes to take. – Rotem Nov 02 '15 at 12:47