Weird behavior of right shift operator (1 32)
It's likely the CPU is actually computing
a >> (b % 32)
in foo
; meanwhile, the 1 >> 32 is a constant expression, so the compiler will fold the constant at compile-time, which somehow gives 0.
Since the standard (C++98 §5.8/1) states that
The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
there is no contradiction having foo(1,32)
and 1>>32
giving different results.
On the other hand, in bar
you provided a 64-bit unsigned value, as 64 > 32 it is guaranteed the result must be 1 / 232 = 0. Nevertheless, if you write
bar(1, 64);
you may still get 1.
Edit: The logical right shift (SHR) behaves like a >> (b % 32/64)
on x86/x86-64 (Intel #253667, Page 4-404):
The destination operand can be a register or a memory location. The count operand can be an immediate value or the CL register. The count is masked to 5 bits (or 6 bits if in 64-bit mode and REX.W is used). The count range is limited to 0 to 31 (or 63 if 64-bit mode and REX.W is used). A special opcode encoding is provided for a count of 1.
However, on ARM (armv6&7, at least), the logical right-shift (LSR) is implemented as (ARMISA Page A2-6)
(bits(N), bit) LSR_C(bits(N) x, integer shift)
assert shift > 0;
extended_x = ZeroExtend(x, shift+N);
result = extended_x<shift+N-1:shift>;
carry_out = extended_x<shift-1>;
return (result, carry_out);
where (ARMISA Page AppxB-13)
ZeroExtend(x,i) = Replicate('0', i-Len(x)) : x
This guarantees a right shift of ≥32 will produce zero. For example, when this code is run on the iPhone, foo(1,32)
will give 0.
These shows shifting a 32-bit integer by ≥32 is non-portable.
C strange behaviour when bit-shifting
Assuming int and unsigned int are 32 bit wide, the integer constant 0xffffffff
is of type unsigned int.
Right shifting an integer with a value of greater or equal the width of the integer will result in undefined behavior1.
This happens in both cases in your example.
Update:
Undefined behavior means that anything can happen. Getting the value 0xffffffff instead of 0 fits this behavior.
You cannot shift by the width of the integer type, because it says so in the standard. You must make a check if the value is greater or equal the width of the type your working with.
1 (Quoted from: ISO/IEC 9899:201x 6.5.7 Bitwise shift operators 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.
Arithmetic right shift gives bogus result?
In C++ as in C, shifts are limited to the size (in bits) of the value shifted. For instance, if unsigned int is 32 bits, then a shift of more than 31 is undefined.
In practice, a common result is that the 5 least-significant bits of the shift amount are used and the higher order bits are ignored; this is due to the compiler producing a machine instruction which does exactly that (eg SHR on x86).
In this case, the shift value is 100000
(decimal) which happens to be 11000011010100000
in binary - the lower 5 bits are zero. So, you're effectively getting a shift by 0. You shouldn't rely on this however; technically, what you're seeing is undefined behaviour.
References:
For C, N1570 section 6.5.7:
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.
For C++, N3690 section 5.8 "[expr.shift]":
The behavior is undefined if the right operand is negative, or greater
than or equal to the length in bits of the promoted left operand.
N1570 is a draft, nearly identical to the released ISO C11 standard; this clause has been pretty much the same since the 1989 ANSI C standard.
N3690 is a recent draft of the C++ standard; I'm not sure whether it's the best one to use, but again, this clause hasn't changed.
What's bad about shifting a 32-bit variable 32 bits?
Yes, it is undefined behaviour.
ISO/IEC 9899:1999 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.
C11 aka ISO/IEC 9899:2011 says the same.
You should first cast b
to the target integer type. Another point is that you should put parentheses around the macro parameters to avoid surprises by operator precedences. Additionally, the comma operator is very useful here, allowing you to avoid the braces, so that the macro can be used as a normal command, closed with a semicolon.
#define splitup(a,b,c) ( (b) = (a) >> 32, (c) = (a) & 0xffffffff )
#define combine(a,b,c) ( (a) = ((unsigned long long)(b) << 32) | (c) )
Additional casts may be necessary for `splitup to silence warnings about precision loss by over-paranoid compilers.
#define splitup(a,b,c) ( (b) = (unsigned long)((a) >> 32), (c) = (unsigned long)((a) & 0xffffffff) )
And please don't even think about using your self-written encryption for production code.
Findbugs warning: Integer shift by 32 -- what does it mean?
From the Java Language Specification:
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f. The shift distance actually used is therefore always in the range 0 to 31, inclusive.
So if b is an int, the expression is identical to
long a = b | c;
which I highly doubt is what is intended. It should probably have been
long a = ((long) b << 32) | c;
(If b is already a long, the code is correct and FindBugs is mistaken about the bug).
Weird behavior of right shift in C (sometimes arithmetic, sometimes logical)
Quoting from https://en.cppreference.com/w/c/language/integer_constant, for an hexadecimal integer constant without any suffix
The type of the integer constant is the first type in which the value can fit, from the list of types which depends on which numeric base and which integer-suffix was used.
int
unsigned int
long int
unsigned long int
long long int(since C99)
unsigned long long int(since C99)
Also, later
There are no negative integer constants. Expressions such as -1 apply the unary minus operator to the value represented by the constant, which may involve implicit type conversions.
So, if an int
has 32 bit in your machine, 0x80000000
has the type unsigned int
as it can't fit an int and can't be negative.
The statement
int x = 0x80000000;
Converts the unsigned int
to an int
in an implementation defined way, but the statement
int x = 0x80000000 >> 3;
Performs a right shift to the unsigned int
before converting it to an int
, so the results you see are different.
EDIT
Also, as M.M noted, the format specifier %x
requires an unsigned integer argument and passing an int
instead causes undefined behavior.
Signed right shift = strange result?
Since x
is a signed quantity, the result of (x & (0xFF << 24))
is 0xFF000000 which is also signed and thus a negative number since the top (sign) bit is set. The >>
operator on int
(a signed value) performs sign extension (Edit: though this behaviour is undefined and implementation-specific) and propagates the sign bit value of 1 as the value is shifted to the right.
You should rewrite the function as follows to work exclusively on unsigned values:
unsigned reverse(unsigned x)
{
unsigned int reversed = 0;
reversed = (x & (0xFF << 24)) >> 24;
reversed |= (x & (0xFF << 16)) >> 8;
reversed |= (x & (0xFF << 8)) << 8;
reversed |= (x & 0xFF) << 24;
return reversed;
}
Weird behaviour of bit-shifting with byte in Java
This happens exactly because byte
is promoted to int
prior performing bitwise operations. int -128
is presented as:
11111111 11111111 11111111 10000000
Thus, shifting right to 7 or 8 bits still leaves 7-th bit 1, so result is narrowed to negative byte
value.
Compare:
System.out.println((byte) (b >>> 7)); // -1
System.out.println((byte) ((b & 0xFF) >>> 7)); // 1
By b & 0xFF
, all highest bits are cleared prior shift, so result is produced as expected.
Why doesn't left bit-shift, , for 32-bit integers work as expected when used more than 32 times?
This is caused due to a combination of an undefined behaviour in C and the fact that code generated for IA-32 processors has a 5 bit mask applied on the shift count. This means that on IA-32 processors, the range of a shift count is 0-31 only. 1
From The C programming language 2
The result is undefined if the right operand is negative, or greater than or equal to the number of bits in the left expression’s type.
From IA-32 Intel Architecture Software Developer’s Manual 3
The 8086 does not mask the shift count. However, all other IA-32 processors (starting with the Intel 286 processor) do mask the shift count to 5 bits, resulting in a maximum count of 31. This masking is done in all operating modes (including the virtual-8086 mode) to reduce the maximum execution time of the instructions.
1 http://codeyarns.com/2004/12/20/c-shift-operator-mayhem/
2 A7.8 Shift Operators, Appendix A. Reference Manual, The C Programming Language
3 SAL/SAR/SHL/SHR – Shift, Chapter 4. Instruction Set Reference, IA-32 Intel Architecture Software Developer’s Manual
Related Topics
Force to Link Against Unused Shared Library
Missing Lboost_Thread-Mt in Mongodb Cpp Driver (Ubuntu Server X64)
Using a Stl Map of Function Pointers
Is a Moved-From Vector Always Empty
Is Std::Cout Guaranteed to Be Initialized
How to Implement Multithread Safe Singleton in C++11 Without Using <Mutex>
Force Gcc to Notify About Undefined References in Shared Libraries
How to Initialize a Const Field in Constructor
Reading from Ifstream Won't Read Whitespace
How to Monitor a Folder with All Subfolders and Files Inside
Memory Stability of a C++ Application in Linux
C Compiler Error from Standard Headers - Undefined C++ Definitions
The Simplest and Neatest C++11 Scopeguard
Does Vector::Erase() on a Vector of Object Pointers Destroy the Object Itself