This question already has answers here:
What happens when you bit shift beyond the end of a variable?
(3 answers)
Closed 3 years ago.
I am currently trying to extract some bits from an address called addr with a 32 bit mask called mask into another variable called result as follows
int addr = 7;
int x = 0;
uint32_t mask = 0xFFFFFFFF;
result = addr & (mask >> (32 - x));
I am expecting result to be 0 when x = 0, and this is confirmed on online bitshift calculators. however in C code, result is 1. Why is that?
You're performing an illegal bitshift.
Shifting by a value greater or equal than the size in bits of the left operand results in undefined behavior. This is documented in section 6.5.7p3 of the C standard:
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.
This means you need to check the value of x, and if it is 0 then just use 0 for the bitmask.
int x = 0;
uint32_t mask = 0xFFFFFFFF;
...
if (x == 0) {
result = 0;
} else {
result = addr & (mask >> (32 - x));
}
From the C standard (6.5.7 Bitwise shift operators)
3 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
Related
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;
}
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.
This question already has answers here:
Shifting a 32 bit integer by 32 bits
(2 answers)
Closed 7 years ago.
When shift count < width of type, it works as expected:
int a = 1 << (8 * sizeof(int) - 1);
printf("%x\n", a); // 80000000
When shift count >= width of type, the result is different every time and there seems no law:
int b = 1 << 8 * sizeof(int); // int b = 1 << (8 * sizeof(int) + 1);
printf("%x\n", b); // such as 59fa2ba8, 5b0f6ba8, 52f46ba8 etc
Well, there is a warning saying warning: shift count >= width of type [-Wshift-count-overflow]. If this can explain the random outcome, then let me put the shift count into a variable:
int k = 8 * sizeof(int);
int c = 1 << k;
int d = 1 << (k + 1);
printf("%x\n", c); // 1
printf("%x\n", d); // 2
The result is totally different from before, this is Circular shift! How to explain this?
int b = 1 << 8 * sizeof(int);
is subject to undefined behavior.
From the C99 Standard:
6.5.7 Bitwise shift operators
3 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.
It's pointless to try to make sense of the outcome of such an operation.
My program is written below:
void main() {
int n =0;
printf("%x", (~0 << (32+ (~n +1) )));
}
As n = 0, ~n = 0xffffffff == -1, so ~n + 1 is equal to 0.
When I execute this program, I get 0xffffffff, which is incorrect as (~0 << 32 ) outputs 0.
When I replace (~n +1) with 0, it outputs 0.
Any help is very much appreciated.
You're shifting a 32-bit wide value by 32 bits.
The result is undefined and could equal mushroom lasagna for all you know.
[C99: 6.5.7/3]: 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.
Any further analysis, then, is folly.
I am working with a mix of C90 and C99 (cannot fully use C99 for reasons I better don't discuss, because they aren't good for my blood pressure and would endanger the life of the person preventing us from moving our code base into the current millennium). Still I am going to quote the C99 standard.
I have code that is roughly like this, when condensed to the bare minimum (test.c):
#include <stdio.h>
unsigned int foo(unsigned int n)
{
unsigned int x, y;
n = n - 264;
x = (n >> 2) + 1;
y = 1U << (x + 2U);
return y;
}
int main(void)
{
printf("%u\n", foo(384));
return 0;
}
Of course the value passed to foo() can conceivably be bigger than the value given here. Still 384 is the lowest value that will trigger the Clang static analyzer (3.4 compiled from the release tag) to spit a warning:
$ clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -analyzer-checker=core -internal-isystem /usr/local/include -internal-isystem $HOME/bin/LLVM/bin/../lib/clang/3.4/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -x c test.c
test.c:8:9: warning: The result of the '<<' expression is undefined
y = 1U << (x + 2U);
~~~^~~~~~~~~~~
1 warning generated.
Now going through the lines one by one:
// n == 384
n = n - 264; // n := 384 - 264
// n == 120
x = (n >> 2) + 1; // x := (120 div 4) + 1
// x == 31
y = 1U << (x + 2U); // y := 1 << 33
So, alright it pushes all the meaningful bits out of the integer, and from my understanding of the following (from here) this should give me simply zero:
6.5.7 Bitwise shift operators
...
4
The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned
type, the value of the result is E1 × 2^E2, reduced modulo one more
than the maximum value representable in the result type. If E1 has a
signed type and nonnegative value, and E1 × 2^E2 is representable in
the result type, then that is the resulting value; otherwise, the
behavior is undefined.
From how I read this, an undefined result can only occur ever, if signed values are involved. However, I took care that all of the values are unsigned, even made it explicit on the literals.
Am I wrong or is the Clang static analyzer overly zealous?
The original incarnation of this code is from Jonathan Bennetts JB01 implementation (version 1.40a) in C++.
In the C99 standard, right before your quoted part:
3
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.
unsigned int in most machines today has 32 bits, that makes left shift 33, undefined behavior.
That same paragraph also says, before the part you quoted, in paragraph 6.5.7.3:
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.
Thus, clang is doing a fine job since the behavior is indeed undefined once you shift more bits than the promoted left operand can hold.