I have written this small program using C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
unsigned int un_i = 1112;
printf ("%d and %d", (1 - un_i), (1 - un_i)/10);
return 0;
}
My expectation is: "-1111 and -111"
But my result is: "-1111 and 429496618"
I don't know why it prints out 429496618 instead of -111. Please explain for me
I use gcc ver 4.4.7 and OS centos with kernel 2.6.32
Thank you very much!
That because un_i
is of type unsigned int
, it does not represent negative values. If you expect the result to be negative, you will need signed type, like int
, try this:
unsigned int un_i = 1112;
printf ("PRINTF: un_i[%d] and u_i/10[%d]\n", (1 - un_i), (1 - (int)un_i)/10);
You expect to print -1111
and -111
. However 1 - un_i
produces a result that is also of type unsigned int
; the result is also always non-negative. If unsigned int
is 32 bits wide (as it is in your case), the result will be 4294966185
; and that divided by 10 would result in 429496618
.
The %d
switch expects a ( signed
) int
, not an unsigned int
. Of that the C11 standard says that when using variable arguments with wrong type the behaviour is undefined, excepting that
one type is a signed integer type, the other type is the corresponding unsigned integer type, and the value is representable in both types
Thus printing 429496618
with %d
has defined behaviour, as this same value is representable as both signed int
and unsigned int
.
However 1 - 1112U
will have the value of UINT_MAX - 1110
, which, when used as an argument to printf
and converted with %d
will lead to undefined behaviour since the UINT_MAX - 1100
value is not representable as a signed int
; getting -1111
printed just happens to be the ( undefined ) behaviour in this case.
Since you really want to use signed numbers, then you should declare your variable un_i
as an int
instead of unsigned int
.
In case you expect to do signed math with numbers greater than int
use long int
or long long int
or even better, types such as int64_t
instead of this unsigned trickery.
Your issue is from Signed and Unsigned conversion.
1, In case of unsigned int un_i = 1112
;
(1 - un_i) = 0xfffffba9 /* first bit is 1 */
Even the first bit is 1, but un_i
is unsigned
, so it treat the first bit as normal value bit , so the first bit will be 0 after division :
(1 - un_i)/10 = 0x1999992a /* first bit is 0 */
printf ("%d", (1 - un_i)/10); /* 0x1999992a = 429496618 because Sign bit is 0 */
2, In case of int sig_i = 1112
, the first bit is treated as Sign bit, and keep it is still 1 (negative) after devision by 10:
(1 - sig_i) = 0xfffffba9 /* first bit is 1 */
(1 - sig_i)/10 = 0xffffff91 /* first bit is 1 */
printf ("%d", (1 - sig_i)/10); /* 0xffffff91 = -111 because Sign bit is 1 */
Please run my code to get the detail result:
unsigned int un_i = 1112;
int sig_i = 1112;
printf ("Unsigned \n%d [hex: %x]\n", (1 - un_i), (1 - un_i));
printf ("and %d [hex: %x]\n", (1 - un_i)/10, (1 - un_i)/10);
printf ("Signed \n%d[hex: %x]\n", (1 - sig_i), (1 - sig_i));
printf ("and %d [hex: %x]\n", (1 - sig_i)/10, (1 - sig_i)/10);
Result
Unsigned
-1111 [hex: fffffba9]
and 429496618 [hex: 1999992a]
Signed
-1111[hex: fffffba9]
and -111 [hex: ffffff91]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.