Question about Bitwise Shift in Microsoft C++ [duplicate] - c++

This question already has answers here:
Why does it make a difference if left and right shift are used together in one expression or not?
(3 answers)
Unexepected behavior from multiple bitwise shifts on the same line [duplicate]
(1 answer)
Why does combining two shifts of a uint8_t produce a different result?
(2 answers)
Closed last year.
I am doing the following bitwise shift in Microsoft C++:
uint8_t arr[3] = {255, 255, 255};
uint8_t value = (arr[1] << 4) >> 4;
The result of these operations confused me quite a bit:
value = 255
However, if I do the bitwise shift separately:
value = (arr[i] << 4);
value = value >> 4;
the answer is different and makes much sense:
value = 15
Can someone explain to me why this happens? I am familiar with the concepts of bitwise shift, or so I believed...
Thanks in advance!
(P.S.: It seems g++ will have the same behavior. I am probably missing some important concepts with bitwise shift. Any help is greatly appreciated!)

In this expression with shift operators
(arr[1] << 4) >> 4;
there is used the integral promotions. That is the operand arr[1] is promoted to an object of the type int and such an object can store the result of the expression arr[i] << 4.
From the C++ 14 Standard (5.8 Shift operators, p.#1)
...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.
Here is a demonstration program
#include <iostream>
#include <iomanip>
#include <type_traits>
#include <cstdint>
int main()
{
uint8_t x = 255;
std::cout << "std::is_same_v<decltype( x << 4 ), int> is "
<< std::boolalpha
<< std::is_same_v<decltype( x << 4 ), int> << '\n';
std::cout << "x << 4 = " << ( x << 4 ) << '\n';
}
The program output is
std::is_same_v<decltype( x << 4 ), int> is true
x << 4 = 4080
As for this code snippet
value = (arr[i] << 4);
value = value >> 4;
then in the first assignment statement the result of the shift operation is truncated.

Expression (arr[1] << 4) will implicitly promote the value of arr[1] to type unsigned int before applying the shift operation, such that the "intermediate" result will not "loose" any bits (cf, for example, the explanation in implicit conversions).
However, when you write value = (arr[i] << 4);, then this "intermediate" result will be converted back to uint_8, and in this step bits get cut off.
See the difference when you write uint8_t value = ((uint8_t)(arr[1] << 4)) >> 4;

Related

What causes the overflow of the type conversion of cfloat's INT32_MIN to size_t? [duplicate]

This question already has answers here:
Why is −1 > sizeof(int)?
(4 answers)
Closed 1 year ago.
Compiling the code, printed below, in Visual Studio 2019 presents the warning:
C26450:... Use a wider type to store the operands.
#include <iostream>
#include <string>
#include <cfloat>
int main()
{
size_t b = 4;
std::cout << std::boolalpha << (b < INT32_MIN) << std::endl;
return 0;
}
the code above returns:
true
Substituting b with the literal 4 returns:
false
INT32_MIN is defined in stdint.h as the literal:
(-2147483647i32 - 1).
What in the '<' operation occurs for this overflow error?
It acts intuitively when b is type cast to int.
Another note, adding the following indicates no overflow error.
std::cout << sizeof(size_t) << std::endl;
std::cout << sizeof(int) << std::endl;
Outputs:
4
4
According to https://en.cppreference.com/w/cpp/types/size_t , size_t is unsigned.
According to https://en.cppreference.com/w/cpp/language/operator_comparison , the < operator causes conversion to the invoking type on the left hand side.
What occurs in the conversion between this literal (integer type?) and size_t for it to become equal to 2147483648?
size_t is an unsigned format. This is due to how data is represented in memory. You would have the same behaviour whit INT32_MIN is exactly 0b10000000000000000000000000000000 which is exactly 2^31 / 2147483648 (unsigned).
if you represent it as a signed 32bit number then it becomes -2^31
you should checkout :
https://www.electronics-tutorials.ws/binary/signed-binary-numbers.html#:~:text=We%20have%20seen%20that%20negative,MSB)%20as%20a%20sign%20bit.&text=The%20representation%20of%20a%20signed,then%20the%20number%20is%20negative.

Why isn't sizeof() printing 16 bytes instead of 8?

Pretty simple program, I'm just testing the sizeof() function and trying to see if it works. If sizeof() really does return things in terms of bits, when I had these two elements, shouldn't it return 16 instead of 8? Since long long is 8 bytes in C++ and I have two elements?
int main()
{
long long whatever[] = {0};
std::cout << whatever[0] << std::endl;
whatever[2] = 10;
std::cout << "The size of this array is " << sizeof(whatever[0] + whatever[2]) << std::endl;
}
You are not measuring the size of an array, but the size of the sum of two long longs. I.e.,
sizeof(whatever[0] + whatever[2])
is essentially the same as
sizeof(long long)
which you point out is 8.
This is undefined behavior
long long whatever[] = {0};
std::cout << whatever[0] << std::endl;
whatever[2] = 10; // BAD
The code statically initializes whatever as an array of one element. Then you assign a value to whatever[2]. The only valid index in that array is 0. Assigning anything to index 1 or 2 overwrites the important stuff on the stack or does other nefarious things.
You probably meant:
long long whatever[2] = {0};
std::cout << whatever[0] << std::endl;
whatever[1] = 10;
std::cout << "The size of this array is " << sizeof(whatever) << std::endl;
You declared an array with one element. So the valid index for this array is 0. As a result using the value equal to 2 as an index value in this expression
whatever[2] = 10;
results in accessing memory beyond the array that invokes undefined behavior.
As for the operator sizeof then it does not evaluate its operand. It only determines the type of its operand and returns the size of an object of this type.
So this expression
sizeof(whatever[0] + whatever[2])
where you may use an invalid index for the array whatever is equivalent to the expression
sizeof( long long )
From the C++ 14 Standard (5.3.3 Sizeof)
1 The sizeof operator yields the number of bytes in the object
representation of its operand. The operand is either an expression,
which is an unevaluated operand (Clause 5), or a parenthesized
type-id.

Need an explanation on a shift syntax in code - C++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I need some further explanation on a code I don't quite understand.
This is a program that takes a num = 25 and starts moving it left with a << syntax.
#include <iostream>
using namespace std;
int main(){
cout << "Shift to the left" << endl;
short numb = 25;
cout << "Starting value: ";
for (int i = sizeof(short)*8 - 1; i >= 0; i--)
cout << (((1 << i) & numb) == 0 ? "0" : "1");
cout << " " << numb << endl;
for (int i = 0; i < sizeof(short)*8; i++){
numb <<= 1;
cout << "Shift" << (i+1 < 10 ? "0" : "")
<< i+1 << " : ";
for (int i = sizeof(short)*8 - 1; i >= 0; i--)
cout << (((1 << i) & numb) == 0 ? "0" : "1");
cout << " " << numb << endl;
}
return 0;
}
After the line where the first for loop is executed (the count line), what value does the & syntax takes into consideration? ((1 << i) & numb)
I don't understand how the program can take ((1 << i) & numb), compares the two and return a value.
Also why do we declare i to be sizeof(short)*8 - 1? Why don't we just type in 16-1? Is there a specific reason to do this or is it just to make the code look more complex?
And an explanation on why we even declare i to be 15-1 would be highly appreciative.
Hope I haven't given you too much, I'm a beginner and I need some guidance with some problems to which answers I can't still yet come up with by myself.
Thanks!
The bitwise shift operators are the right-shift operator (>>), which moves the bits of shift_expression to the right, and the left-shift operator (<<), which moves the bits of shift_expression to the left. There are also two complex operators that can be used to assign the value directly to the value on left. These are the <<= operator and the >>= operator.
The left-shift operator causes the bits in shift-expression to be shifted to the left by the number of positions specified by additive-expression. The bit positions that have been vacated by the shift operation are zero-filled. A left shift is a logical shift (the bits that are shifted off the end are discarded, including the sign bit).
The right-shift operator causes the bit pattern in shift-expression to be shifted to the right by the number of positions specified by additive-expression. For unsigned numbers, the bit positions that have been vacated by the shift operation are zero-filled. For signed numbers, the sign bit is used to fill the vacated bit positions. In other words, if the number is positive, 0 is used, and if the number is negative, 1 is used.
Demo Code:
using namespace std;
int main() {
int a = 1, b = 3;
// a right now is 00000001
// Left shifting it by 3 will make it 00001000, ie, 8
a = a << 3;
cout << a << endl; // Gives output 8
// Right shifting a by 2 will make it 00000010, ie, 2
a = a >> 2;
cout << a << endl; // Gives output 2
return 0;
}
The result of a right-shift of a signed negative number is implementation-dependent. If you left-shift a signed number so that the sign bit is affected, the result is undefined.

Is it more portable to use ~0 or -1 to represent a type with all bits flipped to 1?

I saw an code example today which used the following form to check against -1 for an unsigned 64-bit integer:
if (a == (uint64_t)~0)
Is there any use case where you would WANT to compare against ~0 instead of something like std::numeric_limits<uint64_t>::max() or straight up -1? The original intent was unclear to me as I'd not seen a comparison like this before.
To clarify, the comparison is checking for an error condition where the unsigned integer type will have all of its bits set to 1.
UPDATE
According to https://stackoverflow.com/a/809341/1762276, -1 does not always represent all bits flipped to 1 but ~0 does. Is this correct?
I recommend you to do it exactly as you have shown, since it is the
most straight forward one. Initialize to -1 which will work always,
independent of the actual sign representation, while ~ will sometimes
have surprising behavior because you will have to have the right
operand type. Only then you will get the most high value of an
unsigned type.
I believe this error case is handled so long as ~0 is always case to the correct type (as indicated). So this would suggest that (uint64_t)~0 is indeed a more accurate and portal representation of an unsigned type with all bits flipped?
All of the following seem to be true (GCC x86_x64):
#include <iostream>
#include <limits>
using namespace std;
int main() {
uint64_t a = 0xFFFFFFFFFFFFFFFF;
cout << (int)(a == -1) << endl;
cout << (int)(a == ~0) << endl;
cout << (int)(a == (uint64_t)-1) << endl;
cout << (int)(a == (uint64_t)~0) << endl;
cout << (int)(a == static_cast<uint64_t>(-1)) << endl;
cout << (int)(a == static_cast<uint64_t>(~0)) << endl;
cout << (int)(a == std::numeric_limits<uint64_t>::max()) << endl;
return 0;
}
Result:
1
1
1
1
1
1
1
In general you should be casting before applying the operator, because casting to a wider unsigned type may or may not cause sign extension depending on whether the source type is signed.
If you want a value of primitive type T with all bits set, the most portable approach is ~T(0). It should work on any number-like classes as well.
As Mr. Bingley said, the types from stdint.h are guaranteed to be two's-complement, so that -T(1) will also give a value with all bits set.
The source you reference has the right thought but misses some of the details, for example neither of (T)~0u nor (T)-1u will be the same as ~T(0u) and -T(1u). (To be fair, litb wasn't talking about widening in that answer you linked)
Note that if there are no variables, just an unsuffixed literal 0 or -1, then the source type is guaranteed to be signed and none of the above concerns apply. But why write different code when dealing with literals, when the universally correct code is no more complex?
std::numeric_limits<uint64_t>::max() is same as (uint64_t)~0 witch is same as (uint64_t)-1
look to this example of code:
#include <iostream>
#include <stdint.h>
using namespace std;
int main()
{
bool x = false;
cout << x << endl;
x = std::numeric_limits<uint64_t>::max() == (uint64_t)~0;
cout << x << endl;
x = false;
cout << x << endl;
x = std::numeric_limits<uint64_t>::max() == (uint64_t)-1;
cout << x;
}
Result:
0
1
0
1
so it's more simple to write (uint64_t)~0 or (uint64_t)-1 than std::numeric_limits<uint64_t>::max() in the code.
The fixed-width integer types like uint64_t are guaranteed to be represented in two's complement, so for those -1 and ~0 are equivalent. For the normal integer types (like int or long) this is not necessarily the case, since the C++ standard does not specify their bit representations.

Why the following two programs yield different outputs? (C++, bit operation, VS 2012)

Program 1:
int x = 4 ^ (4>>32);
cout << x << endl;
Output is 4
Program 2:
int x = 4;
int y = x ^ (x>>32);
cout << y << endl;
Output is 0
Both code-snippets induce undefined behavior if int has 32 bit or less. [expr.shift]/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.
Hence an implementation is not in any way obliged to provide consistent results.