This question already has answers here:
Unsigned int in C behaves negative
(8 answers)
Closed 8 years ago.
I want to ask what is the difference between these two cases ?
Case1:
unsigned int i;
for(i=10;i>=0;i--)
printf("%d",i);
It will result in an infinite loop!
Case2:
unsigned int a=-5;
printf("%d",a);
It will print -5 on the screen.
Now the reason for case 1 is that i is declared as unsigned int so it can not take negative values,hence will always be greater than 0.
But in case 2, if a cannot take negative values, why -5 is being printed???
What is the difference between these two cases?
The difference is that you are printing a as a signed integer.
printf("%d",a);
so while a may be unsigned, then the %d is asking to print the binary value as a signed value. If you want to print it as a unsigned value, then use
printf("%u",a);
Most compilers will warn you about incompatible use of of parameters to printf -- so you could probably catch this by looking at all the warnings and fix it.
When a -ve value is assigned to an unsigned variable, it can't hold that value and that value is added to UINT_MAX and finally you get a positive value.
Note that using wrong specifier to print a data type invokes undefined behavior.
See C11: 7.21.6 p(6):
If a conversion specification is invalid, the behavior is undefined.282)
unsigned int a=-5;
printf("%u",a); // use %u to print unsigned
will print the value of UINT_MAX - 5.
i is declared unsigned so it can not take negative values
That is correct. Most optimizing compilers will notice that, drop the condition from the loop, and issue a warning.
In case 2, if a can not take negative values, why -5 is being printed?
Because on your platform int and unsigned int have such a representation that assigning -5 to unsigned int and then passing it to printf preserves the representation of -5 in the form that lets printf produce the "correct" result.
This is true on your platform, but other platforms may be different. That is why the standard considers this behavior undefined (i.e. printf could produce any output at all). If you print using the unsigned format specifier, you will see a large positive number.
Related
I am learning in C and I got a question regarding this conversion.
short int x = -0x52ea;
printf ( "%x", x );
output:
ffffad16
I would like to know how this conversion works because it's supposed to be on a test and we won't be able to use any compilers. Thank you
I would like to know how this conversion works
It is undefined behavior (UB)
short int x = -0x52ea;
0x52ea is a hexadecimal constant. It has the value of 52EA16, or 21,22610. It has type int as it fits in an int, even if int was 16 bit. OP's int is evidently 32-bit.
- negates the value to -21,226.
The value is assigned to a short int which can encode -21,226, so no special issues with assigning this int to a short int.
printf("%x", x );
short int x is passed to a ... function, so goes through the default argument
promotions and becomes an int. So an int with the value -21,226 is passed.
"%x" used with printf(), expects an unsigned argument. Since the type passed is not an unsigned (and not an int with a non-negative value - See exception C11dr §6.5.2.2 6), the result is undefined behavior (UB). Apparently the UB on your machine was to print the hex pattern of a 32-bit 2's complement of -21,226 or FFFFAD16.
If the exam result is anything but UB, just smile and nod and realize the curriculum needs updating.
The point here is that when a number is negative, it's structured in a completely different way.
1 in 16-bit hexadecimal is 0001, -1 is ffff. The most relevant bit (8000) indicates that it's a negative number (admitting it's a signed integer), and that's why it can only go as positive as 32767 (7fff), and as negative as -32768 (8000).
Basically to transform from positive to negative, you invert all bits and sum 1. 0001 inverted is fffe, +1 = ffff.
This is a convention called Two's complement and it's used because it's quite trivial to do arithmetic using bitwise operations when you use it.
This question already has answers here:
Why does printf not print out just one byte when printing hex?
(5 answers)
Printing hexadecimal characters in C
(7 answers)
How to print 1 byte with printf?
(4 answers)
Closed 5 years ago.
Code
char a;
a = 0xf1;
printf("%x\n", a);
Output
fffffff1
printf() show 4 bytes, that exactly we have one byte in a.
What is the reason of this misbehavior?
How can i correct it?
What is the reason of this misbehavior?
This question looks strangely similar to another I have answered; it even contains a similar value (0xfffffff1). In that answer, I provide some information required to understand what conversion happens when you pass a small value (such as a char) to a variadic function such as printf. There's no point repeating that information here.
If you inspect CHAR_MIN and CHAR_MAX from <limits.h>, you're likely to find that your char type is signed, and so 0xf1 does not fit as an integer value inside of a char.
Instead, it ends up being converted in an implementation-defined manner, which for the majority of us means it's likely to end up with one of the high-order bits becoming the sign bit. When these values are promoted to int (in order to pass to printf), sign extension occurs to preserve the value (that is, a char that has a value of -1 should be converted to an int that has a value of -1 as an int, so too is the underlying representation for your example likely to be transformed from 0xf1 to 0xfffffff1).
printf("CHAR_MIN .. CHAR_MAX: %d .. %d\n", CHAR_MIN, CHAR_MAX);
printf("Does %d fit? %s\n", '\xFF', '\xFF' >= CHAR_MIN && '\xFF' <= CHAR_MAX ? "Yes!"
: "No!");
printf("%d %X\n", (char) -1, (char) -1); // Both of these get converted to int
printf("%d %X\n", -1, -1); // ... and so are equivalent to these
How can i correct it?
Declare a with a type that can fit the value 0xf1, for example int or unsigned char.
printf is a variable argument function, so the compiler does its best but cannot check strict compliance between format specifier and argument type.
Here you're passing a char with a %x (integer, hex) format specifier.
So the value is promoted to a signed integer (because > 127: negative char and char is signed on most systems, on yours that's for sure)
Either:
change a to int (simplest)
change a to unsigned char (as suggested by BLUEPIXY) that takes care of the sign in the promotion
change format to %hhx as stated in the various docs (note that on my gcc 6.2.1 compiler hhx is not recognized, even if hx is)
note that the compiler warns you before reaching printf that you have a problem:
gcc -Wall -Wpedantic test.c
test.c: In function 'main':
test.c:6:5: warning: overflow in implicit constant conversion [-Woverflow]
a = 0xf1;
You should use int a instead of char a because char is unsigned and can store only 1 byte from 0 to 255.
And hex number need many storage to store it, and also int storage size is 2 or 4 bytes. So it's good to use int here to store hex number.
I have wrote this program as an exercise to understand how the signed and unsigned integer
work in C.
This code should print simply -9 the addition of -4+-5 stored in variable c
#include <stdio.h>
int main (void) {
unsigned int a=-4;
unsigned int b=-5;
unsigned int c=a+b;
printf("result is %u\n",c);
return 0;
}
When this code run it give me an unexpected result 4294967287.
I also have cast c from unsigned to signed integer printf ("result is %u\n",(int)c);
but also doesn't work.
please someone give explanation why the program doesn't give the exact result?
if this is an exercise in c and signed vs unsigned you should start by thinking - what does this mean?
unsigned int a=-4;
should it even compile? It seems like a contradiction.
Use a debugger to inspect the memory stored at he location of a. Do you think it will be the same in this case?
int a=-4;
Does the compiler do different things when its asked to add unsigned x to unsigned y as opposed to signed x and signed y. Ask the compiler to show you the machine code it generated in each case, read up what the instructions do
Explore investigate verify, you have the opportunity to get really interesting insights into how computers really work
You expect this:
printf("result is %u\n",c);
to print -9. That's impossible. c is of type unsigned int, and %u prints a value of type unsigned int (so good work using the right format string for the argument). An unsigned int object cannot store a negative value.
Going back a few line in your program:
unsigned int a=-4;
4 is of type (signed) int, and has the obvious value. Applying unary - to that value yields an int value of -4.
So far, so good.
Now what happens when you store this negative int value in an unsigned int object?
It's converted.
The language specifies what happens when you convert a signed int value to unsigned int: the value is adjusted to it's within the range of unsigned int. If unsigned int is 32 bits, this is done by adding or subtracting 232 as many times as necessary. In this case, the result is -4 + 232, or 4294967292. (That number makes a bit more sense if you show it in hexadecimal: 0xfffffffc.)
(The generated code isn't really going to repeatedly add or subtract 232; it's going to do whatever it needs to do to get the same result. The cool thing about using two's-complement to represent signed integers is that it doesn't have to do anything. The int value -4 and the unsigned int value 4294967292 have exactly the same bit representation. The rules are defined in terms of values, but they're designed so that they can be easily implemented using bitwise operations.)
Similarly, c will have the value -5 + 232, or 4294967291.
Now you add them together. The mathematical result is 8589934583, but that won't fit in an unsigned int. Using rules similar to those for conversion, the result is reduced to a value that's within the range of unsigned int, yielding 4294967287 (or, in hex, 0xfffffff7).
You also tried a cast:
printf ("result is %u\n",(int)c);
Here you're passing an int argument to printf, but you've told it (by using %u) to expect an unsigned int. You've also tried to convert a value that's too big to fit in an int -- and the unsigned-to-signed conversion rules do not define the result of such a conversion when the value is out of range. So don't do that.
That answer is precisely correct for 32-bit ints.
unsigned int a = -4;
sets a to the bit pattern 0xFFFFFFFC, which, interpreted as unsigned, is 4294967292 (232 - 4). Likewise, b is set to 232 - 5. When you add the two, you get 0x1FFFFFFF7 (8589934583), which is wider than 32 bits, so the extra bits are dropped, leaving 4294967287, which, as it happens, is 232 - 9. So if you had done this calculation on signed ints, you would have gotten exactly the same bit patterns, but printf would have rendered the answer as -9.
Using google, one finds the answer in two seconds..
http://en.wikipedia.org/wiki/Signedness
For example, 0xFFFFFFFF gives −1, but 0xFFFFFFFFU gives 4,294,967,295
for 32-bit code
Therefore, your 4294967287 is expected in this case.
However, what exactly do you mean by "cast from unsigned to signed does not work?"
#include<stdio.h>
#include<conio.h>
main()
{
int i=-5;
unsigned int j=i;
printf("%d",j);
getch();
}
O/p
-----
-5
#include<stdio.h>
#include<conio.h>
main()
{
int i=-5;
unsigned int j=i;
printf("%u",j);
getch();
}
O/p
===
4255644633
Here I am not getting any compilation error .
It is giving -5 when print with the identifier %d and when printing with %u it is printing some garbage value .
The things I want to know are
1) Why compiler ignores when assigned integer with negative number to unsigned int.
2) How it is converting signed to unsigned ?
Who are "we?"
There's no "garbage value", it's probably just the result of viewing the bits of the signed integer as an unsigned. Typically two's complement will result in very large values for many a negative values. Try printing the value in hex to see the pattern more clearly, in decimal they're often hard to decipher.
I'd simply add that the concept of signed or unsigned is something that humans appreciate more than machines.
Assuming a 32-bit machine, your value of -5 is going to be represented internally by the 32-bit value 0xFFFFFFFB (two's complement).
When you insert printf("%d",j); into your source code, the compiler couldn't care less whether j is signed or unsigned, it just shoves 0xFFFFFFFB onto the stack and then a pointer to the "%d" string. The printf function when called looks at the format string, sees the %d and knows from that that it has to interpret the 0xFFFFFFFB as a signed value, hence the reason for it displaying -5 despite j being an unsigned int.
On the other hand, when you write printf("%u",j);, the "%u" makes printf interpret your 0xFFFFFFFB as an unsigned value. That value is 2^32 - 5, or 4294967291.
It's the format string passed to printf that determines how the value will be interpreted, not the type of the variable j.
There's noting unusual in the possibility to assign a negative value to an unsigned variable. The implicit conversion that happens in such cases is perfectly well defined by C language. The value is brought into the range of the target unsigned type in accordance with the rules of modulo arithmetic. The modulo is equal to 2^N, where N is the number of value bits in the unsigned recipient. This is how it has always been in C.
Printing an unsigned int value with %d specifier makes no sense. This specifier requires a signed int argument. Because of this mismatch, the behavior of your first code is undefined.
In other words, you got it completely backwards with regards to which value is garbage and which is not.
Your first code is essentially "printing garbage value" due to undefined behavior. The fact that it happens to match your original value of -5 is just a specific manifestation of undefined behavior.
Meanwhile, the second code is supposed to print a well-defined proper value. It should be result of conversion of -5 to unsigned int type by modulo UINT_MAX + 1. In your case that modulo probably happens to be 2^32 = 4294967296, which is why you are supposed to see 4294967296 - 5 = 4294967291.
How you managed to get 4255644633 is not clear. Your 4255644633 is apparently a result of different code, not the one you posted.
You can and you should get a warning (or perhaps failure) depending on the compiler and the settings.
The value you get is due to twos-complement.
The output in the second case is not a garbage value...
int i=-5;
when converted to binary form the Most Significant Bit is assigned '1' as -5 is a negative number..
but when u use %u the binary form is treated as a normal number and the 1 in MSB is treated a part of normal number..
#include<stdio.h>
int main()
{
unsigned short a=-1;
printf("%d",a);
return 0;
}
This is giving me output 65535. why?
When I increased the value of a in negative side the output is (2^16-1=)65535-a.
I know the range of unsigned short int is 0 to 65535.
But why is rotating in the range 0 to 65535.What is going inside?
#include<stdio.h>
int main()
{
unsigned int a=-1;
printf("%d",a);
return 0;
}
Output is -1.
%d is used for signed decimal integer than why here it is not following the rule of printing the largest value of its(int) range.
Why the output in this part is -1?
I know %u is used for printing unsigned decimal integer.
Why the behavioral is undefined in second code and not in first.?
This I have compiled in gcc compiler. It's a C code
On my machine sizeof short int is 2 bytes and size of int is 4 bytes.
In your implementation, short is 16 bits and int is 32 bits.
unsigned short a=-1;
printf("%d",a);
First, -1 is converted to unsigned short. This results in the value 65535. For the precise definition see the standard "integer conversions". To summarize: the value is taken modulo USHORT_MAX+1.
This value 65535 is assigned to a.
Then for the printf, which uses varargs, the value is promoted back to int. varargs never pass integer types smaller than int, they're always converted to int. This results in the value 65535, which is printed.
unsigned int a=-1;
printf("%d",a);
First line, same as before but modulo UINT_MAX+1. a is 4294967295.
For the printf, a is passed as an unsigned int. Since %d requires an int the behavior is undefined by the C standard. But your implementation appears to have reinterpreted the unsigned value 4294967295, which has all bits set, as as a signed integer with all-bits-set, i.e. the two's-complement value -1. This behavior is common but not guaranteed.
Variable assignment is done to the amount of memory of the type of the variable (e.g., short is 2 bytes, int is 4 bytes, in 32 bit hardware, typically). Sign of the variable is not important in the assignment. What matters here is how you are going to access it. When you assign to a 'short' (signed/unsigned) you assign the value to a '2 bytes' memory. Now if you are going to use '%d' in printf, printf will consider it 'integer' (4 bytes in your hardware) and the two MSBs will be 0 and hence you got [0|0](two MSBs) [-1] (two LSBs). Due to the new MSBs (introduced by %d in printf, migration) your sign bit is hidden in the LSBs and hence printf considers it unsigned (due to the MSBs being 0) and you see the positive value. To get a negative in this you need to use '%hd' in first case. In the second case you assigned to '4 bytes' memory and the MSB got its SIGN bit '1' (means negative) during assignment and hence you see the negative number in '%d' of printf. Hope it explains. For more clarification please comment on the answer.
NB: I used 'MSB' for a shorthand of higher-order byte(s). Please read it according to the context (e.g., 'SIGN bit' will make you read like 'Most Significant Bit'). Thanks.