Undefined behavior of right-shift in C++
Clash Royale CLAN TAG#URR8PPP
up vote
7
down vote
favorite
From cppreference.com:
For unsigned a and for signed a with nonnegative values, the value of
a >> b is the integer part of a/2b . For negative a, the value of a >>
b is implementation-defined (in most implementations, this performs
arithmetic right shift, so that the result remains negative).
In any case, if the value of the right operand is negative or is
greater or equal to the number of bits in the promoted left operand,
the behavior is undefined.
Why do we have an undefined behavior in case the right operand is greater or equal to the number of bits in the promoted left operand?
It seems to me that the result should be 0 (at least for unsigned/positive integers)...
In particular, with g++ (version 4.8.4, Ubuntu):
unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;
gives: 0 1
c++ bit-shift
add a comment |Â
up vote
7
down vote
favorite
From cppreference.com:
For unsigned a and for signed a with nonnegative values, the value of
a >> b is the integer part of a/2b . For negative a, the value of a >>
b is implementation-defined (in most implementations, this performs
arithmetic right shift, so that the result remains negative).
In any case, if the value of the right operand is negative or is
greater or equal to the number of bits in the promoted left operand,
the behavior is undefined.
Why do we have an undefined behavior in case the right operand is greater or equal to the number of bits in the promoted left operand?
It seems to me that the result should be 0 (at least for unsigned/positive integers)...
In particular, with g++ (version 4.8.4, Ubuntu):
unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;
gives: 0 1
c++ bit-shift
6
See: stackoverflow.com/questions/19636539/⦠- not actually a duplicate question of this one, but certainly explains that it is undefined behaviour, and why. Short version: shift instructions in modern processors often won't shift by more than the register bit width.
â davmac
1 hour ago
guaranteing that the result is0
may incur overhead that most of the time you dont need. Why would you shift by more than the number has bits?
â user463035818
1 hour ago
1
Some assembler instructions for rightshift have only 5 bit for the second operand. The first 5 bit of 32 are 0, so you have 1 >> 0 in some assembler languages.
â mch
1 hour ago
You can make your own:unsigned int right_shift(unsigned int x, int shift_amount) if (shift_amount >= std::numeric_limits<unsigned int>::digits) return 0; return x >> shift_amount;
Notice the extra work to check the size? That's why>>
by itself doesn't do that.
â Eljay
1 hour ago
At least onx86
shift instruction considers/masks only lower5
bits of the value, i.e. it's basicallyx >> (num % 32)
(same for<<
). Implementing it as you want would require an expensive (relatively) branch to check if0 < num < 32
.
â Dan M.
1 hour ago
add a comment |Â
up vote
7
down vote
favorite
up vote
7
down vote
favorite
From cppreference.com:
For unsigned a and for signed a with nonnegative values, the value of
a >> b is the integer part of a/2b . For negative a, the value of a >>
b is implementation-defined (in most implementations, this performs
arithmetic right shift, so that the result remains negative).
In any case, if the value of the right operand is negative or is
greater or equal to the number of bits in the promoted left operand,
the behavior is undefined.
Why do we have an undefined behavior in case the right operand is greater or equal to the number of bits in the promoted left operand?
It seems to me that the result should be 0 (at least for unsigned/positive integers)...
In particular, with g++ (version 4.8.4, Ubuntu):
unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;
gives: 0 1
c++ bit-shift
From cppreference.com:
For unsigned a and for signed a with nonnegative values, the value of
a >> b is the integer part of a/2b . For negative a, the value of a >>
b is implementation-defined (in most implementations, this performs
arithmetic right shift, so that the result remains negative).
In any case, if the value of the right operand is negative or is
greater or equal to the number of bits in the promoted left operand,
the behavior is undefined.
Why do we have an undefined behavior in case the right operand is greater or equal to the number of bits in the promoted left operand?
It seems to me that the result should be 0 (at least for unsigned/positive integers)...
In particular, with g++ (version 4.8.4, Ubuntu):
unsigned int x = 1;
cout << (x >> 16 >> 16) << " " << (x >> 32) << endl;
gives: 0 1
c++ bit-shift
c++ bit-shift
asked 1 hour ago
R2B2
833815
833815
6
See: stackoverflow.com/questions/19636539/⦠- not actually a duplicate question of this one, but certainly explains that it is undefined behaviour, and why. Short version: shift instructions in modern processors often won't shift by more than the register bit width.
â davmac
1 hour ago
guaranteing that the result is0
may incur overhead that most of the time you dont need. Why would you shift by more than the number has bits?
â user463035818
1 hour ago
1
Some assembler instructions for rightshift have only 5 bit for the second operand. The first 5 bit of 32 are 0, so you have 1 >> 0 in some assembler languages.
â mch
1 hour ago
You can make your own:unsigned int right_shift(unsigned int x, int shift_amount) if (shift_amount >= std::numeric_limits<unsigned int>::digits) return 0; return x >> shift_amount;
Notice the extra work to check the size? That's why>>
by itself doesn't do that.
â Eljay
1 hour ago
At least onx86
shift instruction considers/masks only lower5
bits of the value, i.e. it's basicallyx >> (num % 32)
(same for<<
). Implementing it as you want would require an expensive (relatively) branch to check if0 < num < 32
.
â Dan M.
1 hour ago
add a comment |Â
6
See: stackoverflow.com/questions/19636539/⦠- not actually a duplicate question of this one, but certainly explains that it is undefined behaviour, and why. Short version: shift instructions in modern processors often won't shift by more than the register bit width.
â davmac
1 hour ago
guaranteing that the result is0
may incur overhead that most of the time you dont need. Why would you shift by more than the number has bits?
â user463035818
1 hour ago
1
Some assembler instructions for rightshift have only 5 bit for the second operand. The first 5 bit of 32 are 0, so you have 1 >> 0 in some assembler languages.
â mch
1 hour ago
You can make your own:unsigned int right_shift(unsigned int x, int shift_amount) if (shift_amount >= std::numeric_limits<unsigned int>::digits) return 0; return x >> shift_amount;
Notice the extra work to check the size? That's why>>
by itself doesn't do that.
â Eljay
1 hour ago
At least onx86
shift instruction considers/masks only lower5
bits of the value, i.e. it's basicallyx >> (num % 32)
(same for<<
). Implementing it as you want would require an expensive (relatively) branch to check if0 < num < 32
.
â Dan M.
1 hour ago
6
6
See: stackoverflow.com/questions/19636539/⦠- not actually a duplicate question of this one, but certainly explains that it is undefined behaviour, and why. Short version: shift instructions in modern processors often won't shift by more than the register bit width.
â davmac
1 hour ago
See: stackoverflow.com/questions/19636539/⦠- not actually a duplicate question of this one, but certainly explains that it is undefined behaviour, and why. Short version: shift instructions in modern processors often won't shift by more than the register bit width.
â davmac
1 hour ago
guaranteing that the result is
0
may incur overhead that most of the time you dont need. Why would you shift by more than the number has bits?â user463035818
1 hour ago
guaranteing that the result is
0
may incur overhead that most of the time you dont need. Why would you shift by more than the number has bits?â user463035818
1 hour ago
1
1
Some assembler instructions for rightshift have only 5 bit for the second operand. The first 5 bit of 32 are 0, so you have 1 >> 0 in some assembler languages.
â mch
1 hour ago
Some assembler instructions for rightshift have only 5 bit for the second operand. The first 5 bit of 32 are 0, so you have 1 >> 0 in some assembler languages.
â mch
1 hour ago
You can make your own:
unsigned int right_shift(unsigned int x, int shift_amount) if (shift_amount >= std::numeric_limits<unsigned int>::digits) return 0; return x >> shift_amount;
Notice the extra work to check the size? That's why >>
by itself doesn't do that.â Eljay
1 hour ago
You can make your own:
unsigned int right_shift(unsigned int x, int shift_amount) if (shift_amount >= std::numeric_limits<unsigned int>::digits) return 0; return x >> shift_amount;
Notice the extra work to check the size? That's why >>
by itself doesn't do that.â Eljay
1 hour ago
At least on
x86
shift instruction considers/masks only lower 5
bits of the value, i.e. it's basically x >> (num % 32)
(same for <<
). Implementing it as you want would require an expensive (relatively) branch to check if 0 < num < 32
.â Dan M.
1 hour ago
At least on
x86
shift instruction considers/masks only lower 5
bits of the value, i.e. it's basically x >> (num % 32)
(same for <<
). Implementing it as you want would require an expensive (relatively) branch to check if 0 < num < 32
.â Dan M.
1 hour ago
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
11
down vote
One of the goals of C++ is to allow for fast, efficient code, "close to the hardware". And on most hardware, an integer right shift or left shift can be implemented by a single opcode. The trouble is, different CPUs have different behavior in this case where the shift magnitude is more than the number of bits.
So if C++ mandated a particular behavior for shift operations, when producing code for a CPU whose opcode behavior doesn't match all the Standard requirements, compilers would need to insert checks and logic to make sure the result is as defined by the Standard in all cases. This would need to happen to almost all uses of the built-in shift operators, unless an optimizer can prove the corner case won't actually happen. The added checks and logic would potentially slow down the program.
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
11
down vote
One of the goals of C++ is to allow for fast, efficient code, "close to the hardware". And on most hardware, an integer right shift or left shift can be implemented by a single opcode. The trouble is, different CPUs have different behavior in this case where the shift magnitude is more than the number of bits.
So if C++ mandated a particular behavior for shift operations, when producing code for a CPU whose opcode behavior doesn't match all the Standard requirements, compilers would need to insert checks and logic to make sure the result is as defined by the Standard in all cases. This would need to happen to almost all uses of the built-in shift operators, unless an optimizer can prove the corner case won't actually happen. The added checks and logic would potentially slow down the program.
add a comment |Â
up vote
11
down vote
One of the goals of C++ is to allow for fast, efficient code, "close to the hardware". And on most hardware, an integer right shift or left shift can be implemented by a single opcode. The trouble is, different CPUs have different behavior in this case where the shift magnitude is more than the number of bits.
So if C++ mandated a particular behavior for shift operations, when producing code for a CPU whose opcode behavior doesn't match all the Standard requirements, compilers would need to insert checks and logic to make sure the result is as defined by the Standard in all cases. This would need to happen to almost all uses of the built-in shift operators, unless an optimizer can prove the corner case won't actually happen. The added checks and logic would potentially slow down the program.
add a comment |Â
up vote
11
down vote
up vote
11
down vote
One of the goals of C++ is to allow for fast, efficient code, "close to the hardware". And on most hardware, an integer right shift or left shift can be implemented by a single opcode. The trouble is, different CPUs have different behavior in this case where the shift magnitude is more than the number of bits.
So if C++ mandated a particular behavior for shift operations, when producing code for a CPU whose opcode behavior doesn't match all the Standard requirements, compilers would need to insert checks and logic to make sure the result is as defined by the Standard in all cases. This would need to happen to almost all uses of the built-in shift operators, unless an optimizer can prove the corner case won't actually happen. The added checks and logic would potentially slow down the program.
One of the goals of C++ is to allow for fast, efficient code, "close to the hardware". And on most hardware, an integer right shift or left shift can be implemented by a single opcode. The trouble is, different CPUs have different behavior in this case where the shift magnitude is more than the number of bits.
So if C++ mandated a particular behavior for shift operations, when producing code for a CPU whose opcode behavior doesn't match all the Standard requirements, compilers would need to insert checks and logic to make sure the result is as defined by the Standard in all cases. This would need to happen to almost all uses of the built-in shift operators, unless an optimizer can prove the corner case won't actually happen. The added checks and logic would potentially slow down the program.
answered 1 hour ago
aschepler
50.4k570125
50.4k570125
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52646507%2fundefined-behavior-of-right-shift-in-c%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
6
See: stackoverflow.com/questions/19636539/⦠- not actually a duplicate question of this one, but certainly explains that it is undefined behaviour, and why. Short version: shift instructions in modern processors often won't shift by more than the register bit width.
â davmac
1 hour ago
guaranteing that the result is
0
may incur overhead that most of the time you dont need. Why would you shift by more than the number has bits?â user463035818
1 hour ago
1
Some assembler instructions for rightshift have only 5 bit for the second operand. The first 5 bit of 32 are 0, so you have 1 >> 0 in some assembler languages.
â mch
1 hour ago
You can make your own:
unsigned int right_shift(unsigned int x, int shift_amount) if (shift_amount >= std::numeric_limits<unsigned int>::digits) return 0; return x >> shift_amount;
Notice the extra work to check the size? That's why>>
by itself doesn't do that.â Eljay
1 hour ago
At least on
x86
shift instruction considers/masks only lower5
bits of the value, i.e. it's basicallyx >> (num % 32)
(same for<<
). Implementing it as you want would require an expensive (relatively) branch to check if0 < num < 32
.â Dan M.
1 hour ago