reinterpret_cast of signed int reference - c++

Why is the result 4294967292 instead of -4 even when both integer types are signed?
#include <iostream>
void f(int & i)
{
i = -4;
}
int main()
{
long long i = 0;
f(reinterpret_cast<int &>(i));
std::cout << i << std::endl;
return 0;
}

long long seems to be 64-bit and int 32-bit number on your architecture. You're using 32-bit integer references, so you only modified the less significant half (you're evidently compiling on an ordinary x86 machine, which uses little endian and two's complement for signed integer representation).
The sign bit, as well as the more significant half are all 0s (as initialized). It would have to be 1s to print the same negative value:
0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1111 1100
^ ^
sign bit of long long sign bit of int
reinterpret_cast only guarantees that you get back your int with another reinterpret_cast, so you either print it as int, or use long long & parameter.

Related

Comparing results after integer promotion

Following situation:
I have macros for storing the complement of a variable together with its original value within a structure. With another macro I want to check if the original value is equal to the complement of the stored complement value. But strangely I do not get the results I may expect.
Simplifying the operation, this results in following situation:
#include <stdbool.h>
#include <stdint.h>
#define CHECKVAR(var__, compl__) ((var__^compl__)==-1);
int main()
{
uint8_t var;
uint8_t complementvar;
var=3;
complementvar=~var;
bool checkOK=CHECKVAR(var,complementvar); /*-> I expect that all bits are set and hereby it is equal to "-1", but instead i get "false" */
return 0;
}
My expectation would be (e.g. on a 32bit system :
after the complement operation complementvar has the value 0xfffffffc (after integer promotion caused by the ~ operator to int and assigning the lvalue to complementvar by implicitly casting it down to uint8).
now to the checking macro:
the bitwise operation leads to an integer promotion on both sides?:
2a). var: 0000 0000 0000 0000 0000 0000 0000 0011;
complementvar: 1111 1111 1111 1111 1111 1111 1111 1100
2b)\ now XOR-ing both var and complementvar shoudl result in
1111 1111 1111 1111 1111 1111 1111 1111
checking the results of the XOR-operation together with -1 (represented as an integer)
1111 1111 1111 1111 1111 1111 1111 1111==1111 1111 1111 1111 1111 1111 1111 1111 shall result in true, but instead i always receive false, because the result of XOR-operation (strangely for me) is 0x000000ff?
What compiler am I using? It's the MSVC++11, but actually the solution should be as compiler independent as possible.
As I have to be portable too, would the results be different with a C compiler?
after the complement operation complementvar has the value 0xfffffffc
No. Look at that code:
uint8_t complementvar;
complementvar=~var;
~var will evaluate to the value you expect, but complementvar has type uint8_t, so the conversion leads to just 0xfc.
In your checking step, this is promoted again to int, but as uint8_t is an unsigned type, no sign extension happens here, you just get 0 bits added. This explains the result you get from xoring (^).

Why does left shift and right shift in the same statement yields a different result?

Consider the following Example:
First Case:
short x=255;
x = (x<<8)>>8;
cout<<x<<endl;
Second Case:
short x=255;
x = x<<8;
x = x>>8;
cout<<x<<endl;
The output in the first case is 255 whereas in the second case is -1. -1 as output does makes sense as cpp does a arithmetic right shift. Here are the intermediate values of x to obtain -1 as output.
x: 0000 0000 1111 1111
x<<8:1111 1111 0000 0000
x>>8:1111 1111 1111 1111
Why doesn't the same mechanism happen in the first case?
The difference is a result of two factors.
The C++ standard does not specify the maximum values of integral types. The standard only specifies the minimum size of each integer type. On your platform, a short is a 16 bit value, and an ints is at least a 32 bit value.
The second factor is two's complement arithmetic.
In your first example, the short value is naturally promoted to an int, which is at least 32 bits, so the left and the right shift operates on an int, before getting converted back to a short.
In your second example, after the first left shift operation the resulting value is once again converted back to a short, and due to two's complement arithmetic, it ends up being a negative value. The right shift ends up sign-extending the negative value, resulting in the final result of -1.
What you just observed is sign extension:
Sign extension is the operation, in computer arithmetic, of increasing the number of bits of a binary number while preserving the number's sign (positive/negative) and value. This is done by appending digits to the most significant side of the number, following a procedure dependent on the particular signed number representation used.
For example, if six bits are used to represent the number "00 1010" (decimal positive 10) and the sign extend operation increases the word length to 16 bits, then the new representation is simply "0000 0000 0000 1010". Thus, both the value and the fact that the value was positive are maintained.
If ten bits are used to represent the value "11 1111 0001" (decimal negative 15) using two's complement, and this is sign extended to 16 bits, the new representation is "1111 1111 1111 0001". Thus, by padding the left side with ones, the negative sign and the value of the original number are maintained.
You rigt shift all the way to the point where your short becomes negative, and when you then shift back, you get the sign extension.
This doesn't happen in the first case, as the shift isn't applied to a short. It's applied to 255 which isn't a short, but the default integral type (probably an int). It only gets casted after it's already been shifted back:
on the stack: 0000 0000 0000 0000 0000 0000 1111 1111
<<8
on the stack: 0000 0000 0000 0000 1111 1111 0000 0000
>>8
on the stack: 0000 0000 0000 0000 0000 0000 1111 1111
convert to short: 0000 0000 1111 1111

1's complement using ~ in C/C++

I am using Visual Studio 2013.
Recently I tried the ~ operator for 1's complement:
int a = 10;
cout << ~a << endl;
Output is -11
But for
unsigned int a = 10;
cout << ~a << endl;
the output is 4294967296
I don't get why the output is -11 in the case of signed int.
Please help me with this confusion.
When you put number 10 into 32-bit signed or unsigned integer, you get
0000 0000 0000 0000 0000 0000 0000 1010
When you negate it, you get
1111 1111 1111 1111 1111 1111 1111 0101
These 32 bits mean 4294967285 as an unsigned integer, or -11 as a signed integer (your computer represents negative integers as Two's complement). They can also mean a 32-bit floating point number or four 8-bit characters.
Bits don't have any "absolute" meaning. They can represent anything, depending on how you "look" at them (which type they have).
The ~ operator performs a ones-complement on its argument, and it does not matter whther the argument is a signed or unsigned integer. It merely flips all the bits, so
0000 0000 0000 1010 (bin) / 10 (dec)
becomes
1111 1111 1111 0101 (bin)
(where, presumably, these numbers are 32 bits wide -- I omitted 16 more 0's and 1's.)
How will cout display the result? It looks at the original type. For a signed integer, the most significant bit is its sign. Thus, the result is always going to be negative (because the most significant bit in 10 is 0). To display a negative number as a positive one, you need the two's complement: inverting all bits, then add 1. For example, -1, binary 111..111, displays as (inverting) 000..000 then +1: 000..001. Result: -1.
Applying this to the one's complement of 10 you get 111..110101 -> inverting to 000...001010, then add 1. Result: -11.
For an unsigned number, cout doesn't do this (naturally), and so you get a large number: the largest possible integer minus the original number.
In memory there is stored 4294967285 in both cases (4294967296 properly a typo, 33 bit?), the meaning of this number depends which signdeness you use:
if it's signed, this the number is -11.
if it's unsigned, then it's 4294967285
different interpretations of the same number.
You can reinterpret it as unsigned by casting it, same result:
int a = 10;
cout << (unsigned int) ~a << endl;
Try this
unsigned int getOnesComplement(unsigned int number){
unsigned onesComplement = 1;
if(number < 1)
return onesComplement;
size_t size = (sizeof(unsigned int) * 8 - 1) ;
unsigned int oneShiftedToMSB = 1 << size;
unsigned int shiftedNumber = number;
for ( size_t bitsToBeShifted = 0; bitsToBeShifted < size; bitsToBeShifted++){
shiftedNumber = number << bitsToBeShifted;
if(shiftedNumber & oneShiftedToMSB){
onesComplement = ~shiftedNumber;
onesComplement = onesComplement >> bitsToBeShifted;
break;
}
}
return onesComplement;
}

int to unsigned int conversion

I'm just amazed to know that I can't convert signed to unsigned int by casting!
int i = -62;
unsigned int j = (unsigned int)i;
I thought I already knew this since I started to use casts, but I can't do it!
You can convert an int to an unsigned int. The conversion is valid and well-defined.
Since the value is negative, UINT_MAX + 1 is added to it so that the value is a valid unsigned quantity. (Technically, 2N is added to it, where N is the number of bits used to represent the unsigned type.)
In this case, since int on your platform has a width of 32 bits, 62 is subtracted from 232, yielding 4,294,967,234.
Edit: As has been noted in the other answers, the standard actually guarantees that "the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type)". So even if your platform did not store signed ints as two's complement, the behavior would be the same.
Apparently your signed integer -62 is stored in two's complement (Wikipedia) on your platform:
62 as a 32-bit integer written in binary is
0000 0000 0000 0000 0000 0000 0011 1110
To compute the two's complement (for storing -62), first invert all the bits
1111 1111 1111 1111 1111 1111 1100 0001
then add one
1111 1111 1111 1111 1111 1111 1100 0010
And if you interpret this as an unsigned 32-bit integer (as your computer will do if you cast it), you'll end up with 4294967234 :-)
This conversion is well defined and will yield the value UINT_MAX - 61. On a platform where unsigned int is a 32-bit type (most common platforms, these days), this is precisely the value that others are reporting. Other values are possible, however.
The actual language in the standard is
If the destination type is unsigned,
the resulting value is the least
unsigned integer congruent to the
source integer (modulo 2^n where n is
the number of bits used to represent
the unsigned type).
i=-62 . If you want to convert it to a unsigned representation. It would be 4294967234 for a 32 bit integer.
A simple way would be to
num=-62
unsigned int n;
n = num
cout<<n;
4294967234
with a little help of math
#include <math.h>
int main(){
int a = -1;
unsigned int b;
b = abs(a);
}
Since we know that i is an int, you can just go ahead and unsigneding it!
This would do the trick:
int i = -62;
unsigned int j = unsigned(i);
From c++17, one can use make_unsigned_t
auto uint_variable = std::make_unsigned_t<int>(-62); //4294967234

How can I access the sign bit of a number in C++?

I want to be able to access the sign bit of a number in C++. My current code looks something like this:
int sign bit = number >> 31;
That appears to work, giving me 0 for positive numbers and -1 for negative numbers. However, I don't see how I get -1 for negative numbers: if 12 is
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1100
then -12 is
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0011
and shifting it 31 bits would make
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001
which is 1, not -1, so why do I get -1 when I shift it?
What about this?
int sign = number < 0;
The result of right-shifting a negative number in C++ is implementation-defined. So, no one knows what right-shifting your -12 should get on your specific platform. You think it should make the above (1), while I say that it can easily produce all-ones pattern, which is -1. The latter is called sign-extended shifting. In sign-extended shifting the sign bit is copied to the right, but never shifted out of its place.
If all you are interested in is the value of the sign bit, then stop wasting time trying to use bitwise operations, like shifts etc. Just compare your number to 0 and see whether it is negative or not.
Because you are shifting signed integer. Cast the integer to unsigned:
int sign_bit = ((unsigned int)number) >> 31;
You can use cmath library
#include <cmath>
and use it like
std::cout << std::signbit(num);
This function get a float value as input and a bool value as output.
true for negative
false for positive
for instance
std::cout << std::signbit(1);
will give you a 0 as output (false)
but while using this function you have to be careful about zero
std::cout << std::signbit(-0.0); // 512 (true)
std::cout << std::signbit(+0.0); // 0 (false)
The output of this lines are not the same.
To remove this problem you can use:
float x = +0.01;
std::cout << (x >= 0 ? (x == 0 ? 0 : 1) : -1);
which give:
0 for 0
1 for positive
-1 for negative
For integers, test number < 0.
For floating point numbers, you may also want take into account the fact that zero has a sign. That is, there exists a -0.0 which is distinct from +0.0. To distinguish the two, you want to use std::signbit.
The >> operator is performing an arithmetic shift, which retains the sign of the number.
bool signbit(double x)
{
return 1.0/x != 1.0/fabs(x);
}
My solution that supports +/-0.
You could do the following:
int t1 = -12;
unsigned int t2 = t1;
t2 = t2>>31;
cout<<t2;
This will work fine for all implementations of c++.
bool signbit(double x)
{
return (__int64)x & 0x8000000000000000LL != 0LL;
}
bool signbit(float x)
{
return (__int32)x & 0x80000000 != 0;
}