Can someone help me understand whats going on with this code. It looks like it is making an integer from an array of bits. Im not sure how its doing that. Why is there a bitwise & operation on OxFF? Inst this just going to produce the same result?
//first take the first 4 bytes read out of the socket into an array and
//make them a 32 bit integer
long ltemp =0;
long ltemp2 = 0;
ltemp = ltemp | (unsigned char)(analog_val_ptr[0] & 0xff);
ltemp = ltemp << 24;
ltemp2 = ltemp2 | (unsigned char)(analog_val_ptr[1] & 0xff);
ltemp2 = ltemp2 << 16;
ltemp = ltemp2 | ltemp;
ltemp2 =0;
ltemp2 = ltemp2 | (unsigned char)(analog_val_ptr[2] & 0xff);
ltemp2 = ltemp2 << 8;
ltemp = ltemp2 | ltemp;
ltemp = ltemp | (unsigned char)(analog_val_ptr[3] & 0xff);
///then convert that integer into a float, passing
That's a very long-winded way of just converting four 8-bit bytes into a 32-bit long.
The anding with 0xff is just ensuring that only the lower 8 bits of each value are used (0xff == binary 11111111).
The bit-shifting (in multiples of 8) is just to get each character into the right position.
The whole thing could be replaced with something like:
unsigned long ltemp = (unsigned char)(analog_val_ptr[0] & 0xff);
ltemp = (ltemp << 8) | (unsigned char)(analog_val_ptr[1] & 0xff);
ltemp = (ltemp << 8) | (unsigned char)(analog_val_ptr[2] & 0xff);
ltemp = (ltemp << 8) | (unsigned char)(analog_val_ptr[3] & 0xff);
Or, alternatively (and assuming they're available), use the correct tools for the job, specifically htonl() and ntohl().
It looks like it's building an integer from an array of bytes. It may be that analog_val_ptr[] is an array of int or short values, and this code is designed to treat each entry as a byte. The masking is to prevent the sign bit from flooding the destination variable.
looks like it is going for an endian independent conversion.
var = 0x ? ? ? ? ? ? ? ?
& & & & & & & &
0x 0 0 0 0 0 0 f f
------------------
0 0 0 0 0 0 ? ?
After the AND operation the lower 8 bits will be found with var & 0xff. Its a way to only cut out the needed portion, masking.
The code above simply pastes the lower bytes of 4 array elements into the variable ltemp as a long int.
Related
I have a long byte array and I want to remove the lower nibble (the lower 4 bits) of every byte and move the rest together such that the result occupies half the space as the input.
For example, if my input is 057ABC23, my output should be 07B2.
My current approach looks like this:
// in is unsigned char*
size_t outIdx = 0;
for(size_t i = 0; i < input_length; i += 8)
{
in[outIdx++] = (in[i ] & 0xF0) | (in[i + 1] >> 4);
in[outIdx++] = (in[i + 2] & 0xF0) | (in[i + 3] >> 4);
in[outIdx++] = (in[i + 4] & 0xF0) | (in[i + 5] >> 4);
in[outIdx++] = (in[i + 6] & 0xF0) | (in[i + 7] >> 4);
}
... where I basically process 8 bytes of input in every loop, to illustrate that I can assume input_length to be divisible by 8 (even though it's probably not faster than processing only 2 bytes per loop). The operation is done in-place, overwriting the input array.
Is there a faster way to do this? For example, since I can read in 8 bytes at a time anyway, the operation could be done on 4-byte or 8-byte integers instead of individual bytes, but I cannot think of a way to do that. The compiler doesn't come up with something itself either, as I can see the output code still operates on bytes (-O3 seems to do some loop unrolling, but that's it).
I don't have control over the input, so I cannot store it differently to begin with.
There is a general technique for bit-fiddling to swap bits around. Suppose you have a 64-bit number, containing the following nibbles:
HxGxFxExDxCxBxAx
Here by x I denote a nibble whose value is unimportant (you want to delete it). The result of your bit-operation should be a 32-bit number HGFEDCBA.
First, delete all the x nibbles:
HxGxFxExDxCxBxAx & *_*_*_*_*_*_*_*_ = H_G_F_E_D_C_B_A_
Here I denote 0 by _, and binary 1111 by * for clarity.
Now, replicate your data:
H_G_F_E_D_C_B_A_ << 4 = _G_F_E_D_C_B_A__
H_G_F_E_D_C_B_A_ | _G_F_E_D_C_B_A__ = HGGFFEEDDCCBBAA_
Notice how some of your target nibbles are together. You need to retain these places, and delete duplicate data.
HGGFFEEDDCCBBAA_ & **__**__**__**__ = HG__FE__DC__BA__
From here, you can extract the result bytes directly, or do another iteration or two of the technique.
Next iteration:
HG__FE__DC__BA__ << 8 = __FE__DC__BA____
HG__FE__DC__BA__ | __FE__DC__BA____ = HGFEFEDCDCBABA__
HGFEFEDCDCBABA__ & ****____****____ = HGFE____DCBA____
Last iteration:
HGFE____DCBA____ << 16 = ____DCBA________
HGFE____DCBA____ | ____DCBA________ = HGFEDCBADCBA____
HGFEDCBADCBA____ >> 32 = ________HGFEDCBA
All x64-86 (and most x86) cpus have SSE2.
For each 16-bit lane do
t = (x & 0x00F0) | (x >> 12).
Then use the pack instruction to truncate each 16-bit lane to 8-bits.
For example, 0xABCD1234 would become 0x00CA0031 then the pack would make it 0xCA31.
#include <emmintrin.h>
void squish_32bytesTo16 (unsigned char* src, unsigned char* dst) {
const __m128i mask = _mm_set1_epi16(0x00F0);
__m128i src0 = _mm_loadu_si128((__m128i*)(void*)src);
__m128i src1 = _mm_loadu_si128((__m128i*)(void*)(src + sizeof(__m128i)));
__m128i t0 = _mm_or_si128(_mm_and_si128(src0, mask), _mm_srli_epi16(src0, 12));
__m128i t1 = _mm_or_si128(_mm_and_si128(src1, mask), _mm_srli_epi16(src1, 12));
_mm_storeu_si128((__m128i*)(void*)dst, _mm_packus_epi16(t0, t1));
}
Just to put the resulting code here for future reference, it now looks like this (assuming the system is little endian, and the input length is a multiple of 8 bytes):
void compress(unsigned char* in, size_t input_length)
{
unsigned int* inUInt = reinterpret_cast<unsigned int*>(in);
unsigned long long* inULong = reinterpret_cast<unsigned long long*>(in);
for(size_t i = 0; i < input_length / 8; ++i)
{
unsigned long long value = inULong[i] & 0xF0F0F0F0F0F0F0F0;
value = (value >> 4) | (value << 8);
value &= 0xFF00FF00FF00FF00;
value |= (value << 8);
value &= 0xFFFF0000FFFF0000;
value |= (value << 16);
inUInt[i] = static_cast<unsigned int>(value >> 32);
}
}
Benchmarked very roughly it's around twice as fast as the code in the question (using MSVC19 /O2).
Note that this is basically the solution anatolyg posted before (just put into code), so upvote that answer instead if you found this helpful.
I have a unsigned short buffer , it contain a hexa values of IP header .
unsigned short buffer = {45,00,00,4E,4E,05,00,10,80,11,0X00,0X00,0A,00,00,1C,1A,00,00,2F};
I added 0X00 , 0X00 in the place of Checksum filed and calculated checksum with the RFC 1071 - Calculating IP header checksum . So it is returning a unsigned short checksum value . Now i need to insert to the Ip buffer .
For example : if my unsigned short checksum value = 55168 and it's Hex value = D780 . Now i need to add D7 , 80 to buffer[11] and buffer[12] . How can i convert unsigned short checksum value and split the Hex value for inserting to the buffer ? If it Hex = D78 , then also i need to add 0D and 78 to the buffer field .
You can separate the values using the bit operators
buffer[11] = (checksum >> 8) & 0xff;
buffer[12] = checksum & 0xff;
The first line shifts the checksum by 8 bits to the right, which is equivalent to dividing by 256 and than ensures, that you only get the information of those remaining 8 bits (0xD7) by using the and(&) operator with 0xff which equals to 1111 1111 in binary representation.
The second line also uses the and operator to save ONLY the last 8 bit of your checksum, which would be 0x80.
You can use expressions of the form buffer[11] = (checkSum & 0xFF00) >> 8; buffer[12] = (checkSum & 0xFF), but you should carefully check if your processor architecture uses big endian or little endian form for representing integers. Hence, it may be that on some systems you have to exchange the expressions to buffer[12] = (checkSum & 0xFF00) >> 8; buffer[11] = (checkSum & 0xFF).
See the following code:
#include <stdio.h>
unsigned short getCheckSum(unsigned short buffer[]) {
return 0xD780;
}
int main(int argc, const char *argv[])
{
unsigned short buffer[20] = {0x45,0x00,0x00,0x4E,0x4E,0x05,0x00,0x10,0x80,0x11,0X00,0X00,0x0A,0x00,0x00,0x1C,0x1A,0x00,0x00,0x2F};
unsigned short checkSum = getCheckSum(buffer);
buffer[11] = (checkSum & 0xFF00) >> 8;
buffer[12] = (checkSum & 0xFF);
for (int i=0; i<20; i++) {
printf("%02X ", buffer[i]);
}
return 0;
}
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);
This program below moves the last (junior) and the penultimate bytes variable i type int. I'm trying to understand why the programmer wrote this
i = (i & LEADING_TWO_BYTES_MASK) | ((i & PENULTIMATE_BYTE_MASK) >> 8) | ((i & LAST_BYTE_MASK) << 8);
Can anyone explain to me in plain English whats going on in the program below.
#include <stdio.h>
#include <cstdlib>
#define LAST_BYTE_MASK 255 //11111111
#define PENULTIMATE_BYTE_MASK 65280 //1111111100000000
#define LEADING_TWO_BYTES_MASK 4294901760 //11111111111111110000000000000000
int main(){
unsigned int i = 0;
printf("i = ");
scanf("%d", &i);
i = (i & LEADING_TWO_BYTES_MASK) | ((i & PENULTIMATE_BYTE_MASK) >> 8) | ((i & LAST_BYTE_MASK) << 8);
printf("i = %d", i);
system("pause");
}
Since you asked for plain english: He swaps the first and second bytes of an integer.
The expression is indeed a bit convoluted but in essence the author does this:
// Mask out relevant bytes
unsigned higher_order_bytes = i & LEADING_TWO_BYTES_MASK;
unsigned first_byte = i & LAST_BYTE_MASK;
unsigned second_byte = i & PENULTIMATE_BYTE_MASK;
// Switch positions:
unsigned first_to_second = first_byte << 8;
unsigned second_to_first = second_byte >> 8;
// Concatenate back together:
unsigned result = higher_order_bytes | first_to_second | second_to_first;
Incidentally, defining the masks using hexadecimal notation is more readable than using decimal. Furthermore, using #define here is misguided. Both C and C++ have const:
unsigned const LEADING_TWO_BYTES_MASK = 0xFFFF0000;
unsigned const PENULTIMATE_BYTE_MASK = 0xFF00;
unsigned const LAST_BYTE_MASK = 0xFF;
To understand this code you need to know what &, | and bit shifts are doing on the bit level.
It's more instructive to define your masks in hexadecimal rather than decimal, because then they correspond directly to the binary representations and it's easy to see which bits are on and off:
#define LAST 0xFF // all bits in the first byte are 1
#define PEN 0xFF00 // all bits in the second byte are 1
#define LEAD 0xFFFF0000 // all bits in the third and fourth bytes are 1
Then
i = (i & LEAD) // leave the first 2 bytes of the 32-bit integer the same
| ((i & PEN) >> 8) // take the 3rd byte and shift it 8 bits right
| ((i & LAST) << 8) // take the 4th byte and shift it 8 bits left
);
So the expression is swapping the two least significant bytes while leaving the two most significant bytes the same.
I have a 32 bit integer, split into parts like this:
--------------------------------------
| Part1 | Part2 | Part 3 |
--------------------------------------
Part 1 higher 16 bits. (Part 2 + Part 3) = lower 16 bits.
Part 2 is 10 bits and Part 3 is 6 bits
I need help on how do we read and update part 1, part2 and part 3 in C program.
Given an integer x with the above format, you can replace Part2 like this:
x = (x & ~(0x3ff << 6)) | (newPart2 << 6);
and Part3 like so:
x = (x & ~0x3f) | newPart3;
This assumes that both newPart2 and newPart3 are e.g. unsigned int with their new values right-adjusted.
int i
To extract the individual parts
part1 = (i & 0xFFFF0000) >> 16
part2 = (i & 0x0000FFC0) >> 6
part3 = (i & 0x0000003F)
To compose the integer
i = (part1 << 16) | (part2 << 6) | (part3)
Try cast to this structure
struct {
uint32_t part_1:16;
uint32_t part_2:10;
uint32_t part_3:6;
} parts;
Could be the one below depending on endianness
struct {
uint32_t part_1:6;
uint32_t part_2:10;
uint32_t part_3:16;
} parts;
Obviously not portable!
Since you need to read and update, a pointer will do. For example, if you 32bit value is called x, you do the following
parts *ptr = (parts *)&x;
ptr->part_2 = <part2 update>
The theory to be used behind this are and, or and shift operations with masks.
To access some bits of the integer, first create a mask where there are ones in the bits you want to be used. Now apply and and(&) operation between the mask and the integer. According to the behavior of the & the bits where the mask is 0 will be 0 and where the mask is 1 will have the value of that bit in the integer. Now that we have only the bits we want we align them to the right, that is done shifting the bits to the right the correct number of positions as to leave the rightmost bit of the mask in the less significant position of the byte.
To write in a part of a byte, we need fist to nullify what was in that part for that we use the negated mask that is used to read that part. Once that part is negated we apply an or(|) operation with the new value that must be aligned to that position.
To read:
unsigned int read_part_1(unsigned int composed) {
return (composed & 0xffff0000) >> 16;
}
unsigned int read_part_2(unsigned int composed) {
return (composed & 0x0000ffc0) >> 6;
}
unsigned int read_part_3(unsigned int composed) {
return (composed & 0x0000003f);
}
To write(val aligned to the right):
unsigned int write_part_1(unsigned int composed, unsigned int val) {
return (composed & ~0xffff0000) | ((val & 0x0000ffff) << 16);
}
unsigned int write_part_2(unsigned int composed, unsigned int val) {
return (composed & ~0x0000ffc0) | ((val & 0x000003ff) << 10);
}
unsigned int write_part_3(unsigned int composed, unsigned int val) {
return (composed & ~0x0000003f) | (val & 0x0000003f);
}