Manually adding a bitmask vs adding a bitwise shift - c

I am trying to add in a left-wise operator to replace the following:
unsigned long bitmask = 0b10000000000000000000000000000000;
printf("%lu\n", bitmask);
unsigned long bitmask2 = (1 << 31)-1;
printf("%lu\n", bitmask2);
However, the closest I'm able to get is -1. If I try doing (1 << 31), it looks like I get an overflow or something. What would be the proper way to do this?
# in the python shell
>>> 0b10000000000000000000000000000000
2147483648
>>> 1<<31
2147483648
>>> 0b10000000000000000000000000000000 == 1<<31
True

Since the type of the result of your shift is unsigned long, you should start with an unsigned long constant:
unsigned long bitmask2 = (1UL << 31) - 1;

Change
unsigned long bitmask2 = (1 << 31)-1;
to something like
unsigned long bitmask2 = (1UL << 31);
instead
The overflow was caused by you are bitwise shifting 31 places for 1 which exceed the boundary of a signed int. Please note that 1 is a signed int literal.

All integer constants like 1 have a type, in this case int. An int is signed and therefore has 31 data bits and 1 sign bit. You cannot left shift data into this sign bit - 1<<31 is a severe undefined behavior bug.
As a rule of thumb, never mix signed operands with bitwise operators. You can fix the bug by adding a 'u' suffix to the integer constant: 1u << 31. Now the type is unsigned int instead, 32 data bits.
Please note that the resulting type of a shift operation is that of the left operand. So there is no need to write for example 1u << 31u.

Related

Incorrect bitwise result

I'm working on a C project for a PIC microcontroller in MikroC and have a function:
void Write_SPI_32(unsigned long Address, unsigned long Data);
That only sometimes works:
Write_SPI_32(0x300000 + 12, 0b10001111000010100000000000000000); //Gives expected result
Write_SPI_32(0x300000 + 12, 0x8f0a0000); //Gives expected result
Write_SPI_32(0x300000 + 12, 2399797248); //Gives expected result
Write_SPI_32(0x300000 + 12, (2 << 30) | (120 << 21) | (160 << 12)); //Gives UNEXPECTED result
How am I managing to noob the bitwise math here?
2 << 30 overflows a 32-bit int, as the nominal result would be 231, but the largest value representable in int would be 231−1, so the behavior is not defined by the C standard.
A typical behavior from a compiler would be that this produces the result −231 (the same bit pattern as 231 but interpreted with two’s complement), then the other operands (120 << 21 and so on) are ORed in. Then, when the argument is converted to a 64-bit unsigned long to pass to Write_SPI_32, this negative int becomes an unsigned long with its high 32 bits set.
You can use (unsigned long) 2 << 30 or 2ul << 30. When shifting, it is often useful to cast the left operand to the ultimate destination type, so that the shift is performed in that type instead of in the default type that results from the integer promotions.

bits shift exceeding width of type in C [duplicate]

This question already has answers here:
warning: left shift count >= width of type
(6 answers)
Closed 1 year ago.
I have a uint64_t variable called vpn and I'm trying to get its left 9 bits.
I know vpn is 45 bits long, so I tried the following:
uint64_t nineMSB = (vpn & (511 << 36)) >> 36;
but I get the following warning:
left shift count >= width of type
Why is that? 511 is 9 ones in binary so 511 << 36 should give me 45 bits, and I'm doing an AND with a uint64_t so the result should not exceed 64 bits..
Thank you!
The constant 511 has type int. Your system most likely has a 32-bit int, so this means you're shifting a value by an amount larger than its bit length. Doing so triggers undefined behavior.
This is dictated by section 6.5.7p3 of the C standard regarding bitwise shift operators:
The integer promotions are performed on each of the operands. The type
of the result is that of the promoted left operand. If the
value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined.
You can fix this by using the ULL suffix on the constant, which will give it type unsigned long long which is guaranteed to be at least 64 bits in length.
uint64_t nineMSB = (vpn & (511ULL << 36)) >> 36;
integer constants without any suffixes or prefixes have type of int. On many systems int is 32bit long, but it can also be only 16bits long (avr port).
uint64_t foo(uint64_t vpn)
{
uint64_t nineMSB = (vpn & (511ULL << 36)) >> 36;
return nineMSB;
}
uint64_t foo1(uint64_t vpn)
{
uint64_t nineMSB = (vpn & ((uint64_t)511 << 36)) >> 36;
return nineMSB;
}

arithmetic right shift shifts in 0s when MSB is 1

As an exercise I have to write the following function:
multiply x by 2, saturating to Tmin / Tmax if overflow, using only bit-wise and bit-shift operations.
Now this is my code:
// xor MSB and 2nd MSB. if diferent, we have an overflow and SHOULD get 0xFFFFFFFF. otherwise we get 0.
int overflowmask = ((x & 0x80000000) ^ ((x & 0x40000000)<<1)) >>31;
// ^ this arithmetic bit shift seems to be wrong
// this gets you Tmin if x < 0 or Tmax if x >= 0
int overflowreplace = ((x>>31)^0x7FFFFFFF);
// if overflow, return x*2, otherwise overflowreplace
return ((x<<1) & ~overflowmask)|(overflowreplace & overflowmask);
now when overflowmask should be 0xFFFFFFFF, it is 1 instead, which means that the arithmetic bit shift >>31 shifted in 0s instead of 1s (MSB got XORed to 1, then shifted to the bottom).
x is signed and the MSB is 1, so according to C99 an arithmetic right shift should fill in 1s. What am I missing?
EDIT: I just guessed that this code isn't correct. To detect an overflow it suffices for the 2nd MSB to be 1.
However, I still wonder why the bit shift filled in 0s.
EDIT:
Example: x = 0xA0000000
x & 0x80000000 = 0x80000000
x & 0x40000000 = 0
XOR => 0x80000000
>>31 => 0x00000001
EDIT:
Solution:
int msb = x & 0x80000000;
int msb2 = (x & 0x40000000) <<1;
int overflowmask = (msb2 | (msb^msb2)) >>31;
int overflowreplace = (x >>31) ^ 0x7FFFFFFF;
return ((x<<1) & ~overflowmask) | (overflowreplace & overflowmask);
Even on twos-complement machines, the behaviour of right-shift (>>) on negative operands is implementation-defined.
A safer approach is to work with unsigned types and explicitly OR-in the MSB.
While you're at it, you probably also want to use fixed-width types (e.g. uint32_t) rather than failing on platforms that don't meet your expectations.
0x80000000 is treated as an unsigned number which causes everything to be converted to unsigned, You can do this:
// xor MSB and 2nd MSB. if diferent, we have an overflow and SHOULD get 0xFFFFFFFF. otherwise we get 0.
int overflowmask = ((x & (0x40000000 << 1)) ^ ((x & 0x40000000)<<1)) >>31;
// this gets you Tmin if x < 0 or Tmax if x >= 0
int overflowreplace = ((x>>31)^0x7FFFFFFF);
// if overflow, return x*2, otherwise overflowreplace
return ((x<<1) & ~overflowmask)|(overflowreplace & overflowmask);
OR write the constants in negative decimals
OR I would store all the constants in const int variables to have them guaranteed signed.
Never use bit-wise operands on signed types. In case of right shift on signed integers, it is up to the compiler if you get an arithmetic or a logical shift.
That's only one of your problems though. When you use a hex integer constant 0x80000000, it is actually of type unsigned int as explained here. This accidentally turns your whole expression (x & 0x80000000) ^ ... into unsigned type because of the integer promotion rule known as "the usual arithmetic conversions". Whereas the 0x40000000 expression is signed int and works as (the specific compiler) expected.
Solution:
All variables involved must be of type uint32_t.
All hex constants involved must be u suffixed.
To get something arithmetic shift portably, you would have to do
(x >> n) | (0xFFFFFFFFu << (32-n)) or some similar hack.

Concatenate two unsigned chars to be one uint16_t

I'm trying to right something that will take two unsigned chars and grab the 4 lower bits of one and concatenate that on to the front of the other 8 bits.
x = 01234567
y = 23458901
doBitWise = 890101234567
Is an example of what I'm looking for.
unsigned char x = someNumber;
unsigned char y = someNumber;
uint16_t result = (x & (1 << 4) - 1) | (y);
But that gives me a warning saying the result is going to be bigger than a uint16_t? Am I missing something?
The warning is because there is arithmetic conversions happening in the expression uint16_t result = (x & (1 << 4) - 1) | (y);. Here (1<<4)-1 will have type int, and x is of type unsigned char, according to the rules of conversion, the result will be of type int, which does not fit into a uint16_t on your platform.
Reference, c11 std 6.3.1.8 on Usual arithmetic conversions:
Otherwise, if the type of the operand with signed integer type can represent
all of the values of the type of the operand with unsigned integer type, then
the operand with unsigned integer type is converted to the type of the
operand with signed integer type.
To get the 4 lower bit of x, use x & 0xF. Also cast it to uint16_t before applying the shift operation,
uint16_t result = (uint16_t)(((x & 0xF) << 8) | y);
This will put the lower 4 bit of x ahead of y. The expression you used will or lower 4 bits of x with y, it does not do what you want.
Thats what Im wanting to do, just take the last 4 bits of y and put it with all of x. Making a 12 bit result
x = 01234567
y = 23458901
doBitWise = 890101234567
In that case, you should left shift the y by 8, and mask the front 4 bits:
uint16_t result = (((unsigned short)y << 8) & 0xF00) | x; //result will be casted to uint16_t
Note: be careful of the operator precedence. + comes before <<, thus parentheses is needed
Note 2: to prevent undefined behavior when int is 16-bit and to ensure that the result of y << 8 will be having at least 16-bit, explicit casting to unsigned short is added (since y is originally unsigned char). Besides, the inserting of x is using bitwise OR operator |.
As others have said the problem here is that before doing arithmetic, narrow integer types are converted to int, a signed type. But the solution to that should be much simpler, just force unsigned arithmetic:
uint16_t result = (x & (1U << 4) - 1U) | (y);
Here, the literals are unsigned, so is then the result of the <<, &, - and then | operators. This is because these operators, if presented with int and unsigned always do a conversion of the int part to unsigned.
For the final conversion from unsigned to uint16_t, this always well defined by modulo arithmetic and no sane compiler should complain about this.

Bit-shift not applying to a variable declaration-assignment one-liner

I'm seeing strange behavior when I try to apply a right bit-shift within a variable declaration/assignment:
unsigned int i = ~0 >> 1;
The result I'm getting is 0xffffffff, as if the >> 1 simply wasn't there. It seems to be something about the ~0, because if I instead do:
unsigned int i = 0xffffffff >> 1;
I get 0x7fffffff as expected. I thought I might be tripping over an operator precedence issue, so tried:
unsigned int i = (~0) >> 1;
but it made no difference. I could just perform the shift in a separate statement, like
unsigned int i = ~0;
i >>= 1;
but I'd like to know what's going on.
update Thanks merlin2011 for pointing me towards an answer. Turns out it was performing an arithmetic shift because it was interpreting ~0 as a signed (negative) value. The simplest fix seems to be:
unsigned int i = ~0u >> 1;
Now I'm wondering why 0xffffffff wasn't also interpreted as a signed value.
It is how c compiler works for signed value. The base literal for number in C is int (in 32-bit machine, it is 32-bit signed int)
You may want to change it to:
unsigned int i = ~(unsigned int)0 >> 1;
The reason is because for the signed value, the compiler would treat the operator >> as an arithmetic shift (or signed shift).
Or, more shortly (pointed out by M.M),
unsigned int i = ~0u >> 1;
Test:
printf("%x", i);
Result:
In unsigned int i = ~0;, ~0 is seen as a signed integer (the compiler should warn about that).
Try this instead:
unsigned int i = (unsigned int)~0 >> 1;

Resources