我用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;
}
我的期望是:“ - 1111和-111”
但我的结果是:“ - 1111和429496618”
我不知道为什么打印出429496618而不是-111。请为我解释
我使用gcc ver 4.4.7和OS centos与内核2.6.32
非常感谢!
答案 0 :(得分:0)
因为un_i
的类型为unsigned int
,所以它不代表负值。如果您希望结果为否定,则需要签名类型,例如int
,请尝试:
unsigned int un_i = 1112;
printf ("PRINTF: un_i[%d] and u_i/10[%d]\n", (1 - un_i), (1 - (int)un_i)/10);
答案 1 :(得分:0)
您希望打印-1111
和-111
。但是1 - un_i
生成的结果也是 unsigned int
;结果也总是非负面的。如果unsigned int
是32位宽(就像你的情况那样),结果将是4294966185
;除以10将导致429496618
。
%d
切换需要(signed
)int
,而不是unsigned int
。其中C11标准规定,当使用错误类型的变量参数时,行为是未定义的,除之外
一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且该值可在两种类型中表示
因此,使用429496618
打印%d
已定义行为,因为此相同值可表示为signed int
和unsigned int
。
但是1 - 1112U
的值为UINT_MAX - 1110
,当用作printf
的参数并使用%d
转换时,会导致未定义的行为< / strong>,因为UINT_MAX - 1100
值无法表示为signed int
;在这种情况下,获得-1111
打印恰好是(未定义)行为。
由于您确实想使用带符号的数字,因此您应该将变量un_i
声明为int
而不是unsigned int
。
如果您希望使用大于int
的数字进行签名数学,请使用long int
或long long int
甚至更好的类型,例如int64_t
,而不是此无符号欺骗。
答案 2 :(得分:-1)
您的问题来自签名和无符号转换。
1,如果是unsigned int un_i = 1112
;
(1 - un_i) = 0xfffffba9 /* first bit is 1 */
即使第一位是1,但un_i
是unsigned
,所以它将第一位视为正常值位,所以第一位将是分裂后为0 :
(1 - un_i)/ 10 = 0x1999992a / *第一位为0 * /
printf ("%d", (1 - un_i)/10); /* 0x1999992a = 429496618 because Sign bit is 0 */
2,在int sig_i = 1112
的情况下,第一位被视为符号位,并且在划分10之后保持为1(负):
(1 - sig_i)= 0xfffffba9 / *第一位是1 * /
(1 - sig_i)/ 10 = 0xffffff91 / *第一位是1 * /
printf ("%d", (1 - sig_i)/10); /* 0xffffff91 = -111 because Sign bit is 1 */
请运行我的代码以获取详细结果:
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);
结果
Unsigned
-1111 [hex: fffffba9]
and 429496618 [hex: 1999992a]
Signed
-1111[hex: fffffba9]
and -111 [hex: ffffff91]