开发者

Why does (1 >> 0x80000000) == 1?

开发者 https://www.devze.com 2023-04-09 17:12 出处:网络
The number 1, right shifted by anything greater than 0, should be 0, correct?Yet I can type in this very simple program which prints 1.

The number 1, right shifted by anything greater than 0, should be 0, correct? Yet I can type in this very simple program which prints 1.

#include <stdio.h>

int main开发者_如何学C()
{
        int b = 0x80000000;
        int a = 1 >> b;
        printf("%d\n", a);
}

Tested with gcc on linux.


6.5.7 Bitwise shift operators:

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.

The compiler is at license to do anything, obviously, but the most common behaviors are to optimize the expression (and anything that depends on it) away entirely, or simply let the underlying hardware do whatever it does for out-of-range shifts. Many hardware platforms (including x86 and ARM) mask some number of low-order bits to use as a shift-amount. The actual hardware instruction will give the result you are observing on either of those platforms, because the shift amount is masked to zero. So in your case the compiler might have optimized away the shift, or it might be simply letting the hardware do whatever it does. Inspect the assembly if you want to know which.


according to the standard, shifting for more than the bits actually existing can result in undefined behavior. So we cannot blame the compiler for that.

The motivation probably resides in the "border meaning" of 0x80000000 that sits on the boundary of the maximum positive and negative together (and that is "negative" having the highmost bit set) and on certain check that should be done and that the compiled program doesn't to to avoid to waste time verifying "impossible" things (do you really want the processor to shift bits 3 billion times?).


It's very probably not attempting to shift by some large number of bits.

INT_MAX on your system is probably 2**31-1, or 0x7fffffff (I'm using ** to denote exponentiation). If that's the case, then In the declaration:

int b = 0x80000000;

(which was missing a semicolon in the question; please copy-and-paste your exact code) the constant 0x80000000 is of type unsigned int, not int. The value is implicitly converted to int. Since the result is outside the bounds of int, the result is implementation-defined (or, in C99, may raise an implementation-defined signal, but I don't know of any implementation that does that).

The most common way this is done is to reinterpret the bits of the unsigned value as a 2's-complement signed value. The result in this case is -2**31, or -2147483648.

So the behavior isn't undefined because you're shifting by value that equals or exceeds the width of type int, it's undefined because you're shifting by a (very large) negative value.

Not that it matters, of course; undefined is undefined.

NOTE: The above assumes that int is 32 bits on your system. If int is wider than 32 bits, then most of it doesn't apply (but the behavior is still undefined).

If you really wanted to attempt to shift by 0x80000000 bits, you could do it like this:

unsigned long b = 0x80000000;
unsigned long a = 1 >> b;    // *still* undefined

unsigned long is guaranteed to be big enough to hold the value 0x80000000, so you avoid part of the problem.

Of course, the behavior of the shift is just as undefined as it was in your original code, since 0x80000000 is greater than or equal to the width of unsigned long. (Unless your compiler has a really big unsigned long type, but no real-world compiler does that.)

The only way to avoid undefined behavior is not to do what you're trying to do.

It's possible, but vanishingly unlikely, that your original code's behavior is not undefined. That can only happen if the implementation-defined conversion of 0x80000000 from unsigned int to int yields a value in the range 0 .. 31. IF int is smaller than 32 bits, the conversion is likely to yield 0.


well read that maybe can help you

expression1 >> expression2

The >> operator masks expression2 to avoid shifting expression1 by too much.

That because if the shift amount exceeded the number of bits in the data type of expression1, all the original bits would be shifted away to give a trivial result.

Now for ensure that each shift leaves at least one of the original bits, the shift operators use the following formula to calculate the actual shift amount:

mask expression2 (using the bitwise AND operator) with one less than the number of bits in expression1.

Example

var x : byte = 15;
// A byte stores 8 bits.
// The bits stored in x are 00001111
var y : byte = x >> 10;
// Actual shift is 10 & (8-1) = 2
// The bits stored in y are 00000011
// The value of y is 3
print(y); // Prints 3

That "8-1" is because x is 8 bytes so the operacion will be with 7 bits. that void remove last bit of original chain bits

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号