This question already has answers here:
bit shifting with unsigned long type produces wrong results
(4 answers)
Closed 5 years ago.
I am trying to create a method to change a range of bits to all 1 using a high and a low and a source. The code works from 0 to 30, then it outputs incorrect numbers. The correct result for setBits(0, 31, 0) should be ffffffff instead of 0.
What is causing my code to reset to zero?
setBits(0,0,0): 1
setBits(0,1,0): 3
setBits(0,2,0): 7
setBits(0,3,0): f
setBits(0,4,0): 1f
setBits(0,5,0): 3f
setBits(0,6,0): 7f
setBits(0,7,0): ff
setBits(0,8,0): 1ff
setBits(0,9,0): 3ff
setBits(0,10,0): 7ff
setBits(0,11,0): fff
setBits(0,12,0): 1fff
setBits(0,13,0): 3fff
setBits(0,14,0): 7fff
setBits(0,15,0): ffff
setBits(0,16,0): 1ffff
setBits(0,17,0): 3ffff
setBits(0,18,0): 7ffff
setBits(0,19,0): fffff
setBits(0,20,0): 1fffff
setBits(0,21,0): 3fffff
setBits(0,22,0): 7fffff
setBits(0,23,0): ffffff
setBits(0,24,0): 1ffffff
setBits(0,25,0): 3ffffff
setBits(0,26,0): 7ffffff
setBits(0,27,0): fffffff
setBits(0,28,0): 1fffffff
setBits(0,29,0): 3fffffff
setBits(0,30,0): 7fffffff
setBits(0,31,0): 0
uint64_t setBits(unsigned low, unsigned high, uint64_t source)
{
assert(high < 64 && (low <= high));
uint64_t mask;
mask = ((1 << (high-low + 1))-1) << low;
uint64_t extracted = mask | source;
return extracted;
}
You need to make the initial bit into the type unsigned long long (or uint64_t) so that it doesn't overflow when bitshifted.
mask = ((1ULL << (high - low + 1)) - 1) << low;
^^^
For number 1 of int type, it'll overflow when leftshifted for 32 bits:
((1 << (high-low + 1))-1) // Where (high-low + 1) == 31 - 0 + 1 == 32
^
00000000 00000000 00000000 00000001 = 1
v <-- Left shift for 32 bits --------<
(1) 00000000 00000000 00000000 00000000 = 0
But that would work for a 64-bit integer type. So change it to 1ULL and the problem is gone.
unsigned is unsigned int, so a 32 bits value, as well as constant 1 which is a signed int, so when you're shifting 1 << (high-low + 1) you're doing it on 32 bits integers.
Use ull to transform all your constants to unsigned 64 bits int during the shifts.
mask = ((1ull << (high-low + 1ull))-1ull) << low
Related
So I have a pointer to a uint8_t array in the form of:
uint8_t* array; // 64-bit array
I need to modify this array by shifting bits to the right and inserting a bit of 0 or 1 at indexes with a power of 2. Thereby generating a 72-bit array.
uint8_t newArr[9];
What is the best way to modify an array so I can add the bits at the specific places I computed. I thought of converting the array to a a char array and then adding the bits one by one. However, is there a faster and more easier method than this.
So if I have a pointer to a bit array in the form of uint8_t like:
000100001 11001111 01101101 11000001 11100000 00101111 11111001 10010010
I would need to modify it into a uint8_t[9] array so that I insert bits I have specified at 0, 1, 2, 4, 8, 16, 32, 64 of the new array to look like: (answer is wrong)
00000000 11001111 11001111 11001111 11001111 01101101 01101101 10010010 00100001
But I don't know how to shift a particular bit to the right without shifting all the bits. For example if I shift all bits starting at index 2 1 to the right and then all bits starting from index 4 to the right by one.
Say you start with the following:
src[0] src[1] src[2] src[3] src[4] src[5] src[6] src[7]
-------- -------- -------- -------- -------- -------- -------- --------
7 6 5 4 3 2 1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
You want to insert at the following positions (octal):
0, 1, 2, 4, 10, 20, 40, 100
That means you want the following:
dst[0] dst[1] dst[2] dst[3] dst[4] dst[5] dst[6] dst[7] dst[8]
-------- -------- -------- -------- -------- -------- -------- -------- --------
1
0 7 6 5 4 3 2 1
76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000
So,
dst[0] = src[0] & 0xFE;
dst[1] = ((src[0] ) << 7) | ((src[1] ) >> 1);
dst[2] = ((src[1] ) << 7) | ((src[2] ) >> 1);
dst[3] = ((src[2] ) << 7) | ((src[3] ) >> 1);
dst[4] = ((src[3] ) << 7) | ((src[4] & 0xFC) >> 1);
dst[5] = ((src[4] ) << 6) | ((src[5] ) >> 2);
dst[6] = ((src[5] ) << 6) | ((src[6] & 0xFC) >> 2);
dst[7] = ((src[6] ) << 5) | ((src[7] & 0xFC) >> 3);
dst[8] = ((src[7] & 0x0E) << 5) | ((src[7] & 0x01) << 3);
(Useless masks omitted.)
You can treat the input array as a 64-bit int to make it faster. Suppose the input and output values are like this
array = aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff gggggggg hhhhhhhh
newArr = aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0 hhh0h000
Then you can get the desired result using this way
uin64_t src = htobe64(*(uint64_t*)array); // operate on big endian
uint64_t* dst = (uint64_t*)newArr;
*dst = (src & 0xFE00'0000'0000'0000) >> 0; // aaaaaaa
*dst |= (src & 0x01FF'FFFF'FC00'0000) >> 1; // abbbbbbbbccccccccddddddddeeeeee
*dst |= (src & 0x0000'0000'03FF'F800) >> 2; // eeffffffffggggg
*dst |= (src & 0x0000'0000'0000'07F0) >> 3; // ggghhhh
*dst = be64toh(*dst); // convert back to the native endian
newArr[8] = ((array[7] & 0x0E) << 4) | ((array[7] & 0x01) << 3); // hhh0h000
To avoid strict aliasing you can change to memcpy to copy from array to src and from dst to newArr
Of course you may need to align the input and output arrays for better performance. On many modern architectures it's also a must
#ifdef _MSC_VER
__declspec(align(8)) uint8_t array[8]; // 64-bit array
__declspec(align(8)) uint8_t newArr[9];
#else
uint8_t array[8] __attribute__((aligned(8))); // 64-bit array
uint8_t newArr[9] __attribute__((aligned(8)));
#endif
On modern x86 with BMI2 you can use the new bit deposit instruction to get the first 8 bytes directly
uint64_t src;
memcpy(&src, &array, sizeof src); // avoid strict aliasing
uin64_t src = htobe64(src);
uint64_t dst = _pdep_u64(src >> 4,
// aaaaaaa0 abbbbbbb bccccccc cddddddd deeeeee0 eeffffff ffggggg0 ggghhhh0
0b11111110'11111111'11111111'11111111'11111110'11111111'11111110'11111110);
// hhh0h000
newArr[8] = _pdep_u32(src, 0b11101000);
*dst = be64toh(*dst); // convert back to the native endian
memcpy(&newArr, &dst, sizeof dst); // avoid strict aliasing
I'm trying to read the pressure value from MPL3115.
At chapter 14.3 the ds says:
The pressure data is stored as a 20-bit unsigned integer with a fractional part. The
OUT_P_MSB (01h), OUT_P_CSB (02h) and bits 7 to 6 of the OUT_P_LSB (03h)
registers contain the integer part in Pascals. Bits 5 to 4 of OUT_P_LSB contain the
fractional component. This value is representative as a Q18.2 fixed point format where
there are 18 integer bits and two fractional bits.
Here my (testing) code for Microchip XMEGA (GCC):
#define MPL3115_ADDRESS 0x60
#define MPL3115_REG_PRESSURE_DATA 0x01
bool _ReadRegister(uint8_t address, uint8_t *readBuf, uint8_t readCount)
{
TWI_MasterWriteRead(&twiMaster, MPL3115_ADDRESS, &address, 1, readCount);
while (twiMaster.status != TWIM_STATUS_READY);
memcpy(readBuf, (void *) twiMaster.readData, readCount);
return true;
}
bool MPL3115_ReadPressure(float *value) {
uint8_t raw[3];
_ReadRegister(MPL3115_REG_PRESSURE_DATA, raw, 3);
uint32_t data = (((uint32_t) raw[0]) << 16) | (((uint32_t) raw[1]) << 8) | raw[2];
uint32_t q18n2 = data >> 4;
*value = (double) q18n2 / 4;
return true;
}
I'm pretty sure the i2c line is working because I can successfully read the temperature from the same chip.
I configured it in barometer mode and 128 oversampling (CTRL_REG1 = 0x38).
In debug mode I read the following values:
raw0 = 0x18
raw1 = 0x25
raw2 = 0x70
data = 1582448
to obtain the pressure in Pascal I have to right shift data of 4 bits:
q18n2 = 98908
now to convert the Q18.2 to float I should multiply for 2^-n or divide for 4:
value = 24727 Pa
This should be in Pascal, so divide for 100 and get mBar = 247.27 mBar... it's unlikely I have such a pressure here! By the way now should be around 1008 mBar.
Are there any mistakes in my thoughts?
you must to right shift data of 6 bits and then add fractional part (2 bits * 0.25).
*value = (raw0 << 10) | (raw1 << 2) | (raw2 >> 6);
*value += 0.25 * ((raw2 >> 4) & 0x03);
I am trying to select bits [0:2] and bits [6:8] of the bit-string 1010000000001. Bits [0:2] are 001 and bits [6:8] are 000. I tried to select these bits with:
int instr = 0x1401;
int src2 = (instr & 0x0006); //get bits [2:0]
int src1 = (instr & 0x01C0) >> 6; //get bits [6:8]
printf("%04x, %04x",src2, src1);
However I am getting that src1 and src2 are both 0000. Can someone please help me understand what I am doing incorrectly so I can select bits [0:2] and [6:8]?
Look at this code:
#include <stdio.h>
int main (void) {
unsigned instr = 0x1401;
unsigned src2 = instr & 0x0007; // 7 in hex == 0000 0000 0111 in binary
unsigned src1 = (instr & 0x01C) >> 6; // 1C in hex == 0001 1100 0000 in binary
printf("%04x, %04x", src2, src1);
}
It masks out the desired bits in instr and shifts them by the correct offset. Also, when doing bit manipulation, unsigned types are preferred.
It's easier to just write a function to calculate any arbitrary bit slice (here using 1 rather than 0 as the least significant bit):
#include <stdio.h>
#include <assert.h>
int bit_select(int num, size_t start, size_t end)
{
assert(end >= start);
const int mask = (1 << (end-start+1)) - 1;
const int shift = start - 1;
return (num & (mask << shift)) >> shift;
}
int main(void)
{
printf("Bits 1...3 of 01100101: %d\n", bit_select(0x65, 1, 3));
printf("Bits 3...3 of 01100101: %d\n", bit_select(0x65, 3, 3));
printf("Bits 4...4 of 01100101: %d\n", bit_select(0x65, 4, 4));
printf("Bits 3...7 of 01100101: %d\n", bit_select(0x65, 3, 7));
return 0;
}
with output:
paul#horus:~/src/sandbox$ ./bitselect
Bits 1...3 of 01100101: 5
Bits 3...3 of 01100101: 1
Bits 4...4 of 01100101: 0
Bits 3...7 of 01100101: 25
paul#horus:~/src/sandbox$
From what I can see if you get the result from 0x1401 & 0x0006 you get 0 and you get the same from 0x1401 & 0x01c0. The bit shift you do on src1 is just 0 shift right 6 bits which is still 0.
Because you provided a wrong mask.
To make life easier if you are using gcc, just provide binary literal rather than hex version so that you can see what you are masking off without pain:
unsigned src2 = instr & 0b111;
int instr = 0x1401;
//results in instr containing (ignoring endian)
//0x00001401
//or in binary
//0b0000 0000 0000 0000 0001 0100 0000 0001
//extracting bits 2:0 is normally done by:
int src2 = instr & 0x00000007;
//extracting bits 8:6 is normally done by:
int src1 = (instr & 0x000001C0) >> 6;
//note that if bit 31 is to be extracted,
//the bit shifting will not work
//due to sign propagation of a negative number
How can I switch the 0th and 3rd bits of each nibble in an integer using only bit operations (no control structures)? What kind of masks do I need to create in order to solve this problem? Any help would be appreciated. For example, 8(1000) become 1(0001).
/*
* SwitchBits(0) = 0
* SwitchBits(8) = 1
* SwitchBits(0x812) = 0x182
* SwitchBits(0x12345678) = 0x82a4c6e1
* Legal Operations: ! ~ & ^ | + << >>
*/
int SwitchBits(int n) {
}
Code:
#include <stdio.h>
#include <inttypes.h>
static uint32_t SwitchBits(uint32_t n)
{
uint32_t bit0_mask = 0x11111111;
uint32_t bit3_mask = 0x88888888;
uint32_t v_bit0 = n & bit0_mask;
uint32_t v_bit3 = n & bit3_mask;
n &= ~(bit0_mask | bit3_mask);
n |= (v_bit0 << 3) | (v_bit3 >> 3);
return n;
}
int main(void)
{
uint32_t i_values[] = { 0, 8, 0x812, 0x12345678, 0x9ABCDEF0 };
uint32_t o_values[] = { 0, 1, 0x182, 0x82A4C6E1, 0x93B5D7F0 };
enum { N_VALUES = sizeof(o_values) / sizeof(o_values[0]) };
for (int i = 0; i < N_VALUES; i++)
{
printf("0x%.8" PRIX32 " => 0x%.8" PRIX32 " (vs 0x%.8" PRIX32 ")\n",
i_values[i], SwitchBits(i_values[i]), o_values[i]);
}
return 0;
}
Output:
0x00000000 => 0x00000000 (vs 0x00000000)
0x00000008 => 0x00000001 (vs 0x00000001)
0x00000812 => 0x00000182 (vs 0x00000182)
0x12345678 => 0x82A4C6E1 (vs 0x82A4C6E1)
0x9ABCDEF0 => 0x93B5D7F0 (vs 0x93B5D7F0)
Note the use of uint32_t to avoid undefined behaviour with sign bits in signed integers.
To obtain a bit, you can mask it out using AND. To get the lowest bit, for example:
x & 0x01
Think about how AND works: both bits must be set. Since we're ANDing with 1, all bits except the first must be 0, because they're 0 in 0x01. The lowest bit will be either 0 or 1, depending on what's in x; said differently, the lowest bit will be the lowest bit in x, which is what we want. Visually:
x = abcd
AND 1 = 0001
--------
000d
(where abcd represent the bits in those slots; we don't know what they are)
To move it to bit 3's position, just shift it:
(x & 0x01) << 3
Visually, again:
x & 0x01 = 000d
<< 3
-----------
d000
To add it in, first, we need to clear out that spot in x for our bit. We use AND again:
x & ~0x08
Here, we invert 0x08 (which is 1000 in binary): this means all bits except bit 3 are set, and when we AND that with x, we get x except for that bit.
Visually,
0x08 = 1000
(invert)
-----------
0111
AND x = abcd
------------
0bcd
Combine with OR:
(x & ~0x08) | ((x & 0x01) << 3)
Visually,
x & ~0x08 = 0bcd
| ((x & 0x01) << 3) = d000
--------------------------
dbcd
Now, this only moves bit 0 to bit 3, and just overwrites bit 3. We still need to do bit 3 → 0. That's simply another:
x & 0x08 >> 3
And we need to clear out its spot:
x & ~0x01
We can combine the two clearing pieces:
x & ~0x09
And then:
(x & ~0x09) | ((x & 0x01) << 3) | ((x & 0x08) >> 3)
That of course handles only the lowest nibble. I'll leave the others as an exercise.
Try below code . Here you should know bitwise operator to implement and correct position to place.Also needs to aware of maintenance ,shifting and toggling basic properties.
#include<stdio.h>
#define BITS_SWAP(x) x=(((x & 0x88888888)>>3) | ((x & 0x11111111)<<3)) | ((x & ~ (0x88888888 | 0x11111111)))
int main()
{
int data=0;
printf("enter the data in hex=0x");
scanf("%x",&data);
printf("bits=%x",BITS_SWAP(data));
return 0;
}
OP
vinay#vinay-VirtualBox:~/c_skill$ ./a.out
enter the data in hex=0x1
bits=8
vinay#vinay-VirtualBox:~/c_skill$ ./a.out
enter the data in hex=0x812
bits=182
vinay#vinay-VirtualBox:~/c_skill$ ./a.out
enter the data in hex=0x12345678
bits=82a4c6e1
vinay#vinay-VirtualBox:~/c_skill$
Try this variant of the xor swap:
uint32_t switch_bits(uint32_t a){
static const mask = 0x11111111;
a ^= (a & mask) << 3;
a ^= (a >> 3) & mask;
a ^= (a & mask) << 3;
return a;
}
Move the low bits to the high bits and mask out the resulting bits.
Move the high bits to the low bits and mask out the resulting bits.
Mask out all bits that have not been moved.
Combine the results with ORs.
Code:
unsigned SwitchBits(unsigned n) {
return ((n << 3) & 0x88888888) | ((n >> 3) & 0x11111111) | (n & 0x66666666);
}
Alternativly, if you would like to be very clever. It can be done with two fewer operations, though this may not actually be faster due to some of the dependicies between instrutions.
Move the high bits to align with the low bits
XOR recording a 0 in the low bit if high an low bits are the same, and a 1 if they are different.
From this, mask out only the low bit of each nibble.
From this, multiply by 9, this will keep the low bit as is, and also copy it to the high bit.
From this, XOR with the original value. in the case that the high and low bit are the same, no change will correctly occure. In the case they are different, they will be effectivly exchanged.
Code:
unsigned SwitchBits(unsigned n) {
return ((((n >> 3) ^ n) & 0x11111111) * 0x9) ^ n;
}
I have a unsigned char array[248]; filled with bytes. Like 2F AF FF 00 EB AB CD EF .....
This Array is my Byte Stream which I store my Data from the UART (RS232) as a Buffer.
Now I want to convert the bytes back to my uint16's and int32's.
In C# I used the BitConverter Class to do this. e.g:
byte[] Array = { 0A, AB, CD, 25 };
int myint1 = BitConverter.ToInt32(bytes, 0);
int myint2 = BitConverter.ToInt32(bytes, 4);
int myint3 = BitConverter.ToInt32(bytes, 8);
int myint4 = BitConverter.ToInt32(bytes, 12);
//...
enter code here
Console.WriteLine("int: {0}", myint1); //output Data...
Is there a similiar Function in C ? (no .net , I use the KEIL compiler because code is running on a microcontroller)
With Regards
Sam
There's no standard function to do it for you in C. You'll have to assemble the bytes back into your 16- and 32-bit integers yourself. Be careful about endianness!
Here's a simple little-endian example:
extern uint8_t *bytes;
uint32_t myInt1 = bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24);
For a big-endian system, it's just the opposite order:
uint32_t myInt1 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
You might be able to get away with:
uint32_t myInt1 = *(uint32_t *)bytes;
If you're careful about alignment issues.
Yes there is. Assume your bytes are in:
uint8_t bytes[N] = { /* whatever */ };
We know that, a 16 bit integer is just two 8 bit integers concatenated, i.e. one has a multiple of 256 or alternatively is shifted by 8:
uint16_t sixteen[N/2];
for (i = 0; i < N; i += 2)
sixteen[i/2] = bytes[i] | (uint16_t)bytes[i+1] << 8;
// assuming you have read your bytes little-endian
Similarly for 32 bits:
uint32_t thirty_two[N/4];
for (i = 0; i < N; i += 4)
thirty_two[i/4] = bytes[i] | (uint32_t)bytes[i+1] << 8
| (uint32_t)bytes[i+2] << 16 | (uint32_t)bytes[i+3] << 24;
// same assumption
If the bytes are read big-endian, of course you reverse the order:
bytes[i+1] | (uint16_t)bytes[i] << 8
and
bytes[i+3] | (uint32_t)bytes[i+2] << 8
| (uint32_t)bytes[i+1] << 16 | (uint32_t)bytes[i] << 24
Note that there's a difference between the endian-ness in the stored integer and the endian-ness of the running architecture. The endian-ness referred to in this answer is of the stored integer, i.e., the contents of bytes. The solutions are independent of the endian-ness of the running architecture since endian-ness is taken care of when shifting.
In case of little-endian, can't you just use memcpy?
memcpy((char*)&myint1, aesData.inputData[startindex], length);
char letter = 'A';
size_t filter = letter;
filter = (filter << 8 | filter);
filter = (filter << 16 | filter);
filter = (filter << 32 | filter);
printf("filter: %#I64x \n", filter);
result: "filter: 0x4141414141414141"