简体   繁体   中英

Print wrong value of unsigned int variable in C

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM