#include <stdio.h>
int main(int argc, char **args){
int d=4294967295;
unsigned e= -1;
printf("\n%u\n%d\n%d\n%u\n%lu\n",d,d,e,e,sizeof(int));
return 0;
}
Output:
4294967295
-1
-1
4294967295
4
Question is, if both signed and unsigned integers can be used to display all kinds of integers by just applying a suitable format string, what's the need for unsigned in the first place?
You are right in so far as (on machines using two's complement and having 32 bit ints) the 0xFFFFFFFF is displayed as -1 with %d, but as 4294967295 with %u.
But strictly speaking this is undefined behaviour.
But the real difference between signed and unsigned variables is in their arithmetic interpretation. The main differences are
with comparing: -1 < 0, but 0 < 4294967295.
with multiplication and division.
Unsigned can hold a larger positive value, and no negative value. Unsigned uses the leading bit as a part of the value, while the signed version uses the left-most-bit to identify if the number is positive or negative. Signed integers can hold both positive and negative numbers.
Related
I have the following C code and I have to understand why the result is a fairly big positive number:
int k;
unsigned int l;
float f;
f=4; l = 1; k = -2;
printf("\n %f", (unsigned int)l+k+f);
The result is a very large number (around 4 billion, max for 32 bit integers), so I suspect it has something to do with the representation of signed negative integers (two's complement) that looks fairly big if we look at it as unsigned.
However I don't quite understand why it behaves this way and what the float has to do with the behavior (if I remove it it stops doing it). Could someone explain how does it do that ? What is the process that happens when adding the numbers that leads to this result ?
The problem is that when you add a signed int to an unsigned, C converts the result to an unsigned int, even negative ones. Since k is negative, it gets re-interpreted as a large positive number before the addition. After that the f is added, but it is small in comparison to negative 2 re-interpreted as a positive number.
Here is a short illustration of the problem:
int k = -2;
unsigned int l = 1;
printf("\n %u", l+k);
This prints 4294967295 on a 32-bit system, because -2 in two's complement representation is 0xFFFFFFFE (demo).
The answer is that when the compiler does the l+k it typecasts the k to unsigned int which turns it into that big number. If you change the order of the vars to this: l+f+k this behavior will not occur.
What happens is that a negative integer is converted to an unsigned integer by adding the maximum unsigned value, plus one, repeatedly to the signed value until it's representable. This is why you see such a large value.
With two's complement, it's the same as truncating or sign extending the value and interpreting it as unsigned which is simple for a computer to do.
Here is the example:
#include <stdio.h>
int main()
{
int x=35;
int y=-35;
unsigned int z=35;
unsigned int p=-35;
signed int q=-35;
printf("Int(35d)=%d\n\
Int(-35d)=%d\n\
UInt(35u)=%u\n\
UInt(-35u)=%u\n\
UInt(-35d)=%d\n\
SInt(-35u)=%u\n",x,y,z,p,p,q);
return 0;
}
Output:
Int(35d)=35
Int(-35d)=-35
UInt(35u)=35
UInt(-35u)=4294967261
UInt(-35d)=-35
SInt(-35u)=4294967261
Does it really matter if I declare the value as signed or unsigned int? Because, C actually only cares about how I read the value from memory. Please help me understand this and I hope you prove me wrong.
Representation of signed integers is up to the underlying platform, not the C language itself. The language definition is mostly agnostic with regard to signed integer representations. Two's complement is probably the most common, but there are other representations such as one's complement and signed magnitude.
In a two's complement system, you negate a value by inverting the bits and adding 1. To get from 5 to -5, you'd do:
5 == 0101 => 1010 + 1 == 1011 == -5
To go from -5 back to 5, you follow the same procedure:
-5 == 1011 => 0100 + 1 == 0101 == 5
Does it really matter if I declare the value as signed or unsigned int?
Yes, for the following reasons:
It affects the values you can represent: unsigned integers can represent values from 0 to 2N-1, whereas signed integers can represent values between -2N-1 and 2N-1-1 (two's complement).
Overflow is well-defined for unsigned integers; UINT_MAX + 1 will "wrap" back to 0. Overflow is not well-defined for signed integers, and INT_MAX + 1 may "wrap" to INT_MIN, or it may not.
Because of 1 and 2, it affects arithmetic results, especially if you mix signed and unsigned variables in the same expression (in which case the result may not be well defined if there's an overflow).
An unsigned int and a signed int take up the same number of bytes in memory. They can store the same byte values. However the data will be treated differently depending on if it's signed or unsigned.
See http://en.wikipedia.org/wiki/Two%27s_complement for an explanation of the most common way to represent integer values.
Since you can typecast in C you can effectively force the compiler to treat an unsigned int as signed int and vice versa, but beware that it doesn't mean it will do what you think or that the representation will be correct. (Overflowing a signed integer invokes undefined behaviour in C).
(As pointed out in comments, there are other ways to represent integers than two's complement, however two's complement is the most common way on desktop machines.)
Does it really matter if I declare the value as signed or unsigned int?
Yes.
For example, have a look at
#include <stdio.h>
int main()
{
int a = -4;
int b = -3;
unsigned int c = -4;
unsigned int d = -3;
printf("%f\n%f\n%f\n%f\n", 1.0 * a/b, 1.0 * c/d, 1.0*a/d, 1.*c/b);
}
and its output
1.333333
1.000000
-0.000000
-1431655764.000000
which clearly shows that it makes a huge difference if I have the same byte representation interpreted as signed or unsigned.
#include <stdio.h>
int main(){
int x = 35, y = -35;
unsigned int z = 35, p = -35;
signed int q = -35;
printf("x=%d\tx=%u\ty=%d\ty=%u\tz=%d\tz=%u\tp=%d\tp=%u\tq=%d\tq=%u\t",x,x,y,y,z,z,p,p,q,q);
}
the result is:
x=35 x=35 y=-35 y=4294967261 z=35 z=35 p=-35 p=4294967261 q=-35 q=4294967261
the int number store is not different, it stored with Complement style in memory,
I can use 0X... the 35 in 0X00000023, and the -35 in 0Xffffffdd, it is not different you use sigend or unsigend. it only output with different sytle. The %d and %u is not different about positive, but the negative the first position is sign, if you output with %u is 0Xffffffdd equal 4294967261, but the %d the 0Xffffffdd can be - 0X00000023 equal -35.
The most fundamental thing that variable's type defines is the way it is stored (that is - read from and written to) in memory and how are the bits interpreted, so your statement can be considered "valid".
You can also look at the problem using conversions. When you store signed and negative value in unsigned variable it gets converted to unsigned. It so happens that this conversion is reversible, so signed -35 converts to unsigned 4294967261, which - when you request it - can be converted to signed -35. That's how 2's complement encoding (see link in other answer) works.
For example:
unsigned int i = ~0;
Result: Max number I can assign to i
and
signed int y = ~0;
Result: -1
Why do I get -1? Shouldn't I get the maximum number that I can assign to y?
Both 4294967295 (a.k.a. UINT_MAX) and -1 have the same binary representation of 0xFFFFFFFF or 32 bits all set to 1. This is because signed numbers are represented using two's complement. A negative number has its MSB (most significant bit) set to 1 and its value determined by flipping the rest of the bits, adding 1 and multiplying by -1. So if you have the MSB set to 1 and the rest of the bits also set to 1, you flip them (get 32 zeros), add 1 (get 1) and multiply by -1 to finally get -1.
This makes it easier for the CPU to do the math as it needs no special exceptions for negative numbers. For example, try adding 0xFFFFFFFF (-1) and 1. Since there is only room for 32 bits, this will overflow and the result will be 0 as expected.
See more at:
http://en.wikipedia.org/wiki/Two%27s_complement
unsigned int i = ~0;
Result: Max number I can assign to i
Usually, but not necessarily. The expression ~0 evaluates to an int with all (non-padding) bits set. The C standard allows three representations for signed integers,
two's complement, in which case ~0 = -1 and assigning that to an unsigned int results in (-1) + (UINT_MAX + 1) = UINT_MAX.
ones' complement, in which case ~0 is either a negative zero or a trap representation; if it's a negative zero, the assignment to an unsigned int results in 0.
sign-and-magnitude, in which case ~0 is INT_MIN == -INT_MAX, and assigning it to an unsigned int results in (UINT_MAX + 1) - INT_MAX, which is 1 in the unlikely case that unsigned int has a width (number of value bits for unsigned integer types, number of value bits + 1 [for the sign bit] for signed integer types) smaller than that of int and 2^(WIDTH - 1) + 1 in the common case that the width of unsigned int is the same as the width of int.
The initialisation
unsigned int i = ~0u;
will always result in i holding the value UINT_MAX.
signed int y = ~0;
Result: -1
As stated above, only if the representation of signed integers uses two's complement (which nowadays is by far the most common representation).
~0 is just an int with all bits set to 1. When interpreted as unsigned this will be equivalent to UINT_MAX. When interpreted as signed this will be -1.
Assuming 32 bit ints:
0 = 0x00000000 = 0 (signed) = 0 (unsigned)
~0 = 0xffffffff = -1 (signed) = UINT_MAX (unsigned)
Paul's answer is absolutely right. Instead of using ~0, you can use:
#include <limits.h>
signed int y = INT_MAX;
unsigned int x = UINT_MAX;
And now if you check values:
printf("x = %u\ny = %d\n", UINT_MAX, INT_MAX);
you can see max values on your system.
No, because ~ is the bitwise NOT operator, not the maximum value for type operator. ~0 corresponds to an int with all bits set to 1, which, interpreted as an unsigned gives you the max number representable by an unsigned, and interpreted as a signed int, gives you -1.
You must be on a two's complement machine.
Look up http://en.wikipedia.org/wiki/Two%27s_complement, and learn a little about Boolean algebra, and logic design. Also learning how to count in binary and addition and subtraction in binary will explain this further.
The C language used this form of numbers so to find the largest number you need to use 0x7FFFFFFF. (where you use 2 FF's for each byte used and the leftmost byte is a 7.) To understand this you need to look up hexadecimal numbers and how they work.
Now to explain the unsigned equivalent. In signed numbers the bottom half of numbers are negative (0 is assumed positive so negative numbers actually count 1 higher than positive numbers). Unsigned numbers are all positive. So in theory your highest number for a 32 bit int is 2^32 except that 0 is still counted as positive so it's actually 2^32-1, now for signed numbers half those numbers are negative. which means we divide the previous number 2^32 by 2, since 32 is an exponent we get 2^31 numbers on each side 0 being positive means the range of an signed 32 bit int is (-2^31, 2^31-1).
Now just comparing ranges:
unsigned 32 bit int: (0, 2^32-1)
signed 32 bit int: (-2^31, 2^32-1)
unsigned 16 bit int: (0, 2^16-1)
signed 16 bit int: (-2^15, 2^15-1)
you should be able to see the pattern here.
to explain the ~0 thing takes a bit more, this has to do with subtraction in binary. it's just adding 1 and flipping all the bits then adding the two numbers together. C does this for you behind the scenes and so do many processors (including the x86 and x64 lines of processors.)
Because of this it's best to store negative numbers as though they are counting down, and in two's complement the added 1 is also hidden. Because 0 is assumed positive thus negative numbers can't have a value for 0, so they automatically have -1 (positive 1 after the bit flip) added to them. when decoding negative numbers we have to account for this.
Can you guys please explain the below program
int main()
{
int max = ~0;
printf("%d\n",max);
return 0;
}
AFAIK ~ will flip the bits. In this case i.e ~0 will set all the bits into 1. So max variable should contain MAX value but I am getting o/p as -1. So can anyone here please tell me why I am getting o/p as -1.
Why did you expect to obtain the "max value"? In 2's-complement signed representation all-1 bit pattern stands for -1. It is just the way it is.
Maximum value in 2's-complement signed representation is represented by 01111...1 bit pattern (i.e the first bit is 0). What you got is 1111...1, which is obviously negative since the very first bit - sign bit - is 1.
If you want an example where complemented zero produces a "max value", use unsigned representation
int main() {
unsigned max = ~0u;
printf("%u\n", max);
}
That is the correct output since you are using the int data type which is signed. You need to read about two's complement negative representation. All one bits is not the maximum negative value, it is -1 as your program outputs. Maximum negative signed value is most significant bit set and all the remaining bits zero, 0x80000000 in the 32-bit case. Maximum positive signed value is 0x7fffffff in the 32-bit case.
The above answers have already covered the reason behind ~0 having value -1.
If you are looking for max integer value, then you can include the limits.h library and use the constants declared in that library
INT_MAX gives you the maximum signed integer value.
UINT_MAX gives you the maximum unsigned integer value.
#include <stdio.h>
#include <limits.h>
int main()
{
printf( "Max signed int value: %d \n", INT_MAX);
printf("Max unsigned int value: %u \n", UINT_MAX );
return 0;
}
This question was a long time ago, but for posterity's sake:
It might help you to see it better if you print ~0 as both int and hex as follows:
printf("compliment of zero %d\n", (~0));
printf("compliment of zero 0x%x\n", (~0));
Output:
Compliment of zero -1
Compliment of zero 0xffffffff
In the following code segment what will be:
the result of function
value of x
value of y
{
unsigned int x=-1;
int y;
y = ~0;
if(x == y)
printf("same");
else
printf("not same");
}
a. same, MAXINT, -1
b. not same, MAXINT, -MAXINT
c. same , MAXUINT, -1
d. same, MAXUINT, MAXUINT
e. not same, MAXINT, MAXUINT
Can someone explain me how its works or can just explain the snippet??
I know it's about two's complement n etc..
What is the significance of MAXINT and -1 ?
It is because of unsigned int and int thing - am I right ?
unsigned int x=-1;
1 is an integer literal and has type int (because it fits in an int). Unary - applied to an int causes no further promotion so -1 is an int with value -1.
When converted to an unsigned int modulo 2^N arithmetic is used where N is the number of value bits in an unsigned int. x has the value 2^N - 1 which is UINT_MAX (What's MAX_UNIT?).
int y;
y = ~0;
Again 0 is type int, in C all the allowed representations of int must have all the value bits of an int representing 0 as 0. Again no promotion happens for unary ~ so ~0 is an int with all value bits being 1. What it's value is is implementation dependent but it is negative (the sign bit will be set) so definitely neither of UINT_MAX or INT_MAX. This value is stored in y unchanged.
if(x == y)
printf("same");
else
printf("not same");
In this comparison y will be converted to unsigned int in order to be compared with x which is already an unsigned int. As y has an implementation value, the value after conversion to unsigned int is still implementation defined (although the conversion itself is modulo 2^N and fully specified). The result of the comparison is still implementation defined.
So in conclusion:
implementation defined, UINT_MAX, implementation defined
In practice on ones' complement:
not same, UINT_MAX, -0 (aka 0)
sign plus magnitude:
not same, UINT_MAX, INT_MIN
two's complement:
same, UINT_MAX, -1
Its pretty easy. The twos complement representation of -1 is 0xFFFFFFFF. Hence that is what x contains.
The complement operator (~) flips all the bits. So the complement of 0 is a 32-bit number with all the bits set to 1 or 0xFFFFFFFF.
Edit: As pointed out int he comments. The answer is not A. If it was then it would be saying 0x7FFFFFFF and 0xFFFFFFFF are the same. They're not. The real answer is C (Assuming MAXUNIT is a typo ;)).
If you run this program, you will see that the answer a is wrong and c is the correct answer:
#include <stdio.h>
#include <limits.h>
int main() {
unsigned int x=-1;
int y;
y = ~0;
if(x == y)
printf("same\n");
if(x==INT_MAX) printf("INT_MAX\n");
if(x==UINT_MAX) printf("UINT_MAX\n");
else
printf("not same");
return 0;
}
It's because of twos-complement
The flipping of the bits results in a bit pattern that matches -1
Since in the first unsigned int, you put -1, but from the unsigned int point of view it is 0xFFFFFFFF (this is how negative integers are stored into a computer); in the second case the bitwise not does not look at the "kind" at all and "transform" 0 into 1 and viceversa, so all zeros of 0 becomes 1 (looking at bits), so you obtain 0xFFFFFFFF.
The next question is, why comparing an unsigned integer with a signed integer does not distinguish them? (numerically 4294967295 is not equal to -1 of course, even though their representation in a computer is the same). Indeed it could, but clearly C does not mandate such a distinction, and it is "natural", since processor aren't able to do it of their own (I am not sure about this last sentence being always true, ... but it is for most processor): to take into account this distinction in asm, you have to add extra code.
From the C point of view, you have to decide if to cast int into unsigned int, or signed int into unsigned int. But a negative number can't be cast into a unsigned one, of course, and on the other hand, an unsigned number could cause overflow (e.g. for 4294967295 you need a 64bit register (or a 33bit regster!) to be able to have it and still be able to calculate its negative value)...
So likely the most natural thing is to avoid strange casting, and permit a "cpu like" comparison, which in this case lead to 0xFFFFFFFF (-1 on 32 bit) compared to 0xFFFFFFFF (~0 on 32bit), which are the same, and more in genereal one can be considered as MAXUINT (the maximum unsigned integer that can be hold) and the other as -1. (Take a look at your machine limits.h include to check it)