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?
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);
Related
What would be the fastest way possible to reverse the nibbles (e.g digits) of a hexadecimal number in C++?
Here's an example of what I mean : 0x12345 -> 0x54321
Here's what I already have:
unsigned int rotation (unsigned int hex) {
unsigned int result = 0;
while (hex) {
result = (result << 4) | (hex & 0xF);
hex >>= 4;
}
return result;
}
This problem can be split into two parts:
Reverse the nibbles of an integer. Reverse the bytes, and swap the nibble within each byte.
Shift the reversed result right by some amount to adjust for the "variable length". There are std::countl_zero(x) & -4 (number of leading zeroes, rounded down to a multiple of 4) leading zero bits that are part of the leading zeroes in hexadecimal, shifting right by that amount makes them not participate in the reversal.
For example, using some of the new functions from <bit>:
#include <stdint.h>
#include <bit>
uint32_t reverse_nibbles(uint32_t x) {
// reverse bytes
uint32_t r = std::byteswap(x);
// swap adjacent nibbles
r = ((r & 0x0F0F0F0F) << 4) | ((r >> 4) & 0x0F0F0F0F);
// adjust for variable-length of input
int len_of_zero_prefix = std::countl_zero(x) & -4;
return r >> len_of_zero_prefix;
}
That requires C++23 for std::byteswap which may be a bit optimistic, you can substitute it with some other byteswap.
Easily adaptable to uint64_t too.
i would do it without loops based on the assumption that the input is 32 bits
result = (hex & 0x0000000f) << 28
| (hex & 0x000000f0) << 20
| (hex & 0x00000f00) << 12
....
dont know if faster, but I find it more readable
I need to compare given text data with checkSumCalculator method and I try to send the data with command method. I find and changed the code according to my own needs. But I dont understand some parts.
How can 0x00 hex char will be increase with given data? and how/what is the point of comparing check_data with 0xFF? How to extract (check_data & 0xFF) from 0x100 hex? I am very confused.
void Widget::command()
{
std::string txt = "<DONE:8022ff";
unsigned char check_sum = checkSumCalculator(&txt[0], txt.size());
QString reply= QString::fromStdString(txt) + QString("%1>").arg(check_sum, 2, 16,
QChar('0'));
emit finished(replyMessage, true);
}
static unsigned char checkSumCalculator(void *data, int length)
{
unsigned char check_data = 0x00;
for (int i = 0; i < lenght; i++)
check_data+= ((unsigned char*)data)[i];
check_data = (0x100 - (check_data & 0xFF)) & 0xFF;
return check_data;
}
checkSumCalculator starts by adding together all the values of the buffer in data. Because the type of data is unsigned char, this sum is done modulo 0x100 (256), 1 more than the maximum value an unsigned char can handle (0xFF = 255); the value is said to "wrap around" ((unsigned char) (0xFF + 1) = 256) is again 0).
These two lines:
check_data = (0x100 - (check_data & 0xFF)) & 0xFF;
return check_data;
are really more complicated than it's needed. All that would be needed would be:
return -check_data;
That is, at the end it negates the value. Because the arithmetic is modulo 256, this is essentially the same as flipping the bits and adding 1 (-check_data = ~check_data + 1). This is instead implemented in a more convoluted way:
check_data & 0xFF doesn't do much, because it's a bitwise AND with all the possible bits that can be set on an unsigned char. The value is promoted to an unsigned int (due to C's default integer promotions) where all the bits higher than the lower 8 are necessarily 0. So this is the same as (unsigned int)check_data. Ultimately, this promotion has no bearing on the result.
Subtracting from 0x100 is the same as -check_data, as far as the lower 8 bits are concerned (which what we end up caring about).
The final & 0xFF is also redundant because even though the expression was promoted to unsigned int, it will converted as an unsigned char by returning.
I have a uint32_t as follows:
uint32_t midiData=0x9FCC00;
I need to separate this uint32_t into smaller parts so that 9 becomes its own entity, F becomes its own entity, and CC becomes its own entity. If you're wondering what I am doing, I am trying to break up the parts of a MIDI message so that they are easier to manage in my program.
I found this solution, but the problem is I don't know how to apply it to the CC section, and that I am not sure that this method works with C++.
Here is what I have so far:
uint32_t midiData=0x9FCC00;
uint32_t status = 0x0FFFFF & midiData; // Retrieve 9
uint32_t channel = (0xF0FFFF & midiData)>>4; //Retrieve F
uint32_t note = (0xFF00FF & midiData) >> 8; //Retrieve CC
Is this correct for C++? Reason I ask is cause I have never used C++ before and its syntax of using the > and < has always confused me (thus why I tend to avoid it).
You can use bit shift operator >> and bit masking operator & in C++ as well.
There are, however, some issues on how you use it:
Operator v1 & v2 gives a number built from those bits that are set in both v1 and v2, such that, for example, 0x12 & 0xF0 gives 0x10, not 0x02. Further, bit shift operator takes the number of bits, and a single digit in a hex number (which is usually called a nibble), consists of 4 bits (0x0..0xF requires 4 bits). So, if you have 0x12 and want to get 0x01, you have to write 0x12 >>4.
Hence, your shifts need to be adapted, too:
#define BITS_OF_A_NIBBLE 4
unsigned char status = (midiData & 0x00F00000) >> (5*BITS_OF_A_NIBBLE);
unsigned char channel = (midiData & 0x000F0000) >> (4*BITS_OF_A_NIBBLE);
unsigned char note = (midiData & 0x0000FF00) >> (2*BITS_OF_A_NIBBLE);
unsigned char theRest = (midiData & 0x000000FF);
You have it backwards, in a way.
In boolean logic (the & is a bitwise-AND), ANDing something with 0 will exclude it. Knowing that F in hex is 1111 in binary, a line like 0x9FCC00 & 0x0FFFFF will give you all the hex digits EXCEPT the 9, the opposite of what you want.
So, for status:
uint32_t status = 0xF000000 & midiData; // Retrieve 9
Actually, this will give you 0x900000. If you want 0x9 (also 9 in decimal), you need to bitshift the result over.
Now, the right bitshift operator (say, X >> 4) means move X 4 bits to the right; dividing by 16. That is 4 bits, not 4 hex digits. 1 hex digit == 4 bits, so to get 9 from 0x900000, you need 0x900000 >> 20.
So, to put them together, to get a status of 9:
uint32_t status = (0xF000000 & midiData) >> 20;
A similar process will get you the remaining values you want.
In general I'd recommend shift first, then mask - it's less error prone:
uint8_t cmd = (midiData >> 16) & 0xff;
uint8_t note = (midiData >> 8) & 0x7f; // MSB can't be set
uint8_t velocity = (midiData >> 0) & 0x7f; // ditto
and then split the cmd variable:
uint8_t status = (cmd & 0xf0); // range 0x00 .. 0xf0
uint8_t channel = (cmd & 0x0f); // range 0 .. 15
I personally wouldn't bother mapping the status value back into the range 0 .. 15 - it's commonly understood that e.g. 0x90 is a "note on", and not the plain value 9.
For example:
I got an input = 0x5A ( 0101 1010 ).
I want to store the first 4 bits or the last 4 bit.
unsigned char lower = input & 0xF;
unsigned char upper = (input >> 4) & 0xF;
Note that the last & 0xF is there in case your data type contains more bits than 8.
just use the & operator to apply a mask:
input = 0x5a & 0xf0;
this would yield 0b01010000. Depending on what you want you could shift the selected bits to the right like
input = (0x5a & 0xf0)>>4;
So to get to the lower half you would use
input = 0x5a & 0x0f;
Is there a better way from hex to char?
char one = static_cast<char>(0x01);
(asking because of this --> C++ using pointers, nothing is passed )
Also is there a fast way to make a char array out of hex values (eg. 0x12345678 to a char array)?
You can try this:
std::string hexify(unsigned int n)
{
std::string res;
do
{
res += "0123456789ABCDEF"[n % 16];
n >>= 4;
} while(n);
return std::string(res.rbegin(), res.rend());
}
Credits to STL for the "index into char array" trick.
Also beware when printing chars, which are signed on some platforms. If you want 128 to print as 80 rather than FFFFFFFF, you have to prevent it from being treated as -1 by converting to unsigned char first: hexify((unsigned char)(c));
What do you intend to be stored in the variable one?
The code as written will store the ASCII character 0x01 into one. This is a control character, not a printable character. If you're looking for the digit 1, then you need to say so explicitly:
char one = '1';
That stores the actual character, not the ASCII code 0x01.
If you are trying to convert a number into the string representation of that number, then you need to use one of these mechanisms. If instead, you are trying to treat a 32-bit integer as a sequence of 4 bytes, each of which is an ASCII character, that is a different matter. For that, you could do this:
uint32_t someNumber = 0x12345678;
std::string myString(4, ' ');
myString[0] = static_cast<char>((someNumber >> 24) & 0xFF);
myString[1] = static_cast<char>((someNumber >> 16) & 0xFF);
myString[2] = static_cast<char>((someNumber >> 8) & 0xFF);
myString[3] = static_cast<char>((someNumber) & 0xFF);