int main()
{
int x = -2;
cout << (1<<x) << endl;
cout << (1<<-2) << endl;
}
Here the (1<<x) prints 1073741824 (how is this calculated)
Whereas (1<<-2) prints a garbage value.
And why do these two return different answers?
According to 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
The same is written in the C++ Standard (C++20, 7.6.7 Shift operators)
... The operands shall be of integral or unscoped enumeration type and
integral promotions are performed. The type of the result is that
of the promoted left operand. The behavior is undefined if the right
operand is negative, or greater than or equal to the width of the
promoted left operand.
In the standard, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf
Page 118, Section 5.8.1:
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
Meaning the compiler can do whatever it wants here - all bets are off.
Related
I'm trying to find information about shift's size type in C++. For example:
int x = 1;
char char_var = 1;
short short_var = 1;
int int_var = 1;
long long_var = 1;
long long long_long_var = 1;
x = x << char_var; // works
x = x << short_var; // works
x = x << int_var; // works
x = x << long_var; // works
x = x << long_long_var; // works
So what type does C++ use for the shift size?
It is explained in [expr.shift]/1: (N4860)
The operands shall be of integral or unscoped enumeration type and integral promotions are performed
Unlike most other binary operators, the usual arithmetic conversions are not performed. The integral promotions mean that in your examples the operands of type char and short are promoted to int (on normal systems) and the others are unchanged.
It can be any type: https://en.cppreference.com/w/cpp/language/operator_arithmetic
In fact the compiler will decide how to cast, and might use intermediate type as it whish. What is garanteed is that if both a and b are positive, the result of a << b is well defined and has the same type as a.
If a or b is negative, the result is undefined and implementation dependent.
The standard §8.5.7 says:
The operands shall be of integral or unscoped enumeration type and
integral promotions are performed. The type of the result is that of
the promoted left operand. 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.
So, to me the right operand should be promoted. That means it will be promoted to int, unsigned int, long etc. You can read the whole paragraph with different rules depending on the type of your variable
Is left-shifting a negative int Undefined Behavior in C++11?
The relevant Standard passages here are from 5.8:
2/The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated
bits are zero-filled. If E1 has an unsigned type, the value of the
result is E1 × 2E2, reduced modulo one more than the maximum value
representable in the result type. Otherwise, if E1 has a signed type
and non-negative value, and E1×2E2 is representable in the result
type, then that is the resulting value; otherwise, the behavior is
undefined.
The part that confuses me is:
Otherwise, if E1 has a signed type and non-negative value, and E1×2E2
is representable in the result type, then that is the resulting value;
otherwise, the behavior is undefined.
Should this be interpreted to mean that left-shifting any negative number is UB? Or does it only mean if you LS a negative and the result doesn't fit in the result type, then it's UB?
Moreover, the preceding clause says:
1/The shift operators << and >> group left-to-right.
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
The operands shall be of integral or unscoped enumeration type and
integral promotions are performed.
The type of the result is that of the promoted left operand. 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.
This makes it explicit that using a negative number for one of the operands is UB. If it were UB to use a negative for the other operand, I would expect that to be made clear here as well.
So, bottom line, is:
-1 << 1
Undefined Behavior?
#Angew provided a psudocode interpretation of the Standardese which succinctly expresses one possible (likely) valid interpretation. Others have questioned whether this question is really about the applicability of the language "behavior is undefined" versus our (StackOverflow's) use of the phrase "Undefined Behavior." This edit is to provide some more clarification on what I'm trying to ask.
#Angew's interpretation of the Standardese is:
if (typeof(E1) == unsigned integral)
value = E1 * 2^E2 % blah blah;
else if (typeof(E1) == signed integral && E1 >= 0 && representable(E1 * 2^E2))
value = E1 * 2^E2;
else
value = undefined;
What this question really boils down to is this -- is the correct interpretation actually:
value = E1 left-shift-by (E2)
switch (typeof(E1))
{
case unsigned integral :
value = E1 * 2^E2 % blah blah;
break;
case signed integral :
if (E1 >= 0)
{
if (representable(E1 * 2^E2))
{
value = E1 * 2^E2;
}
else
{
value = undefined;
}
}
break;
}
?
Sidenote, in looking at this in terms of psudocode makes it fairly clear in my mind that #Agnew's interpretation is the correct one.
Yes, I would say it's undefined. If we translate the standardese to pseudo-code:
if (typeof(E1) == unsigned integral)
value = E1 * 2^E2 % blah blah;
else if (typeof(E1) == signed integral && E1 >= 0 && representable(E1 * 2^E2))
value = E1 * 2^E2;
else
value = undefined;
I'd say the reason why they're explicit about the right-hand operand and not about the left-hand one is that the paragrpah you quote (the one with the right-hand operand case) applies to both left and right shifts.
For the left-hand operand, the ruling differs. Left-shifting a negative is undefined, right-shifting it is implementation-defined.
Should this be interpreted to mean that left-shifting any negative number is UB?
Yes, the behavior is undefined when given any negative number. The behavior is only defined when both of the following are true:
the number is non-negative
E1 × 2E2 is representable in the result type
That's literally what "if E1 has a signed type and non-negative value, and E1×2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined," is saying:
if X and Y
then Z
else U
Answer as per the Question:
The question really is:
Can we equate the term "behavior is undefined" equates exactly to the term "Undefined Behavior".
As it is currently worded it means "Undefined Behavior."
Personal comment about the situation
But I am not convinced that is the authors intention.
If it is the authors intention, then we should probably have a note explaining why. But I am more inclined to believe the author meant that the result of that operation is undefined because the representation of negative numbers is not explicitly defined by the standard. If the representation of negative numbers is not explicitly defined for negatives, then moving the bits around would lead to an undefined value.
Either way, the wording (or explanation) needs to be tightened/expanded to make it less ambiguous.
The following code outputs 0,1,32,33. Which is counter intuitive to say the least. But if I replace the literal 1 with the type annonated constant "ONE", the loop runs fine.
This is with gcc 4.6.2 and -std=c++0x.
#include<iostream>
#include<cstdint>
using namespace std;
int main()
{
int64_t bitmask = 3;
int64_t k;
const int64_t ONE = 1;
cout<<"bitmask = "<<bitmask<<endl;
for(k=0; k<64; k++)
{
if(bitmask & (1<<k))
{
cout<<"k="<<k<<endl;
}
}
return 0;
}
EDIT
Question: As Ben pointed out, 1 is seen to be 32 bit wide by default. Why is it not promoted to 64 bits when it's co-operand is 64 bits.
SOLUTION
No. << does not require that each side have the same type. After all, why make the right side an int64_t when the maximum shift available fits in a char? The promotion only occurs when you are dealing with arithmetic operators, not all operators.
Copied from Bill's comments below
This is a problem: (1<<k).
1 is a integral literal that fits in an int.
If int has fewer than 64 bits on your platform, then (1<<k) will have undefined behavior toward the end of the loop, when k is large. In your case, the compiler is using an Intel bitshift instruction, and the undefined behavior comes out the way Intel defines shifts larger than the operand size -- the high bits are ignored.
You probably want (1LL<<k)
What the standard says (section 5.8 expr.shift):
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. 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.
This in contrast to the wording "The usual arithmetic conversions are performed for
operands of arithmetic or enumeration type." which is present for e.g. addition and subtraction operators.
This language didn't change between C++03 and C++11.
Is the following undefined and why?
int i = 0xFF;
unsigned int r = i << 24;
The behaviour is technically undefined unless the int type has more than 32 bits.
From C++11, 5.8/2 (describing an expression E1 << E2):
if E1 has a signed type and non-negative value, and E1×2E2 is representable
in the result type, then that is the resulting value; otherwise, the behavior is undefined.
The result type of i << 24 is (signed) int; if that has 32 bits or less, then 0xff * 2^24 == 0xff000000 is not representable (the maximum representable 32-bit signed value being 0x7fffffff), so behaviour is undefined as specified in that clause.
According to N3242 section 5.8 Shift operators:
The shift operators << and >> group left-to-right.
shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expression
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. 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.
So my answer? Depends on the number of bits in your left operand (which depends on your system).
If you have some variable (on the stack) and you left or right bit shift beyond its end what happens?
i.e.
byte x = 1;
x >> N;
What if x is a pointer to memory cast to a byte and you do the same thing?
byte* x = obtain pointer from somewhere;
*x = 1;
*x >> N;
It does not (necessarily) become zero. The behavior is undefined (C99 §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.
(C++0x §5.8, "Shift operators"):
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.
The storage of the value being shifted has no effect on any of this.
I think you're confused about what bitshifts do. They are arithmetic operators equivalent to multiplication or division by a power of 2 (modulo some weirdness about how C treats negative numbers). They do not move any bits in memory. The only way the contents of any variable/memory get changed are if you assign the result of the expression back somewhere.
As for what happens when the righthand operand of a bitshift operator is greater than or equal to the width of the type of the lefthand expression, the behavior is undefined.
I think you're confused. x >> y does not actually change x in the first place. It calculates a new value.
As Stephen noted, y must not be negative, and it must be less than "the width of the promoted left operand" (read up on type promotion). But otherwise, bits that shift "off the end" are simply discarded. 1 >> 2 (notice that 2 is not negative, and it is less than the number of bits used to represent 1, which is probably 32 but certainly at least 16) evaluates to 0.