在 C 语言中,unsigned int
用于存储正值。然而,当我运行以下代码时:
unsigned int x = -12;
printf("%d", x);
输出仍为-12。我以为它应该输出:12,或者我是误解了什么吗?在 C 语言中,unsigned int
用于存储正值。然而,当我运行以下代码时:
unsigned int x = -12;
printf("%d", x);
输出仍为-12。我以为它应该输出:12,或者我是误解了什么吗?-12
是一个有符号整数(可能为32位),将具有十六进制值0xFFFFFFF4
。编译器会生成代码,将这个有符号整数移动到你的无符号整数x
中,它也是一个32位实体。编译器假设你等号右侧只有正值,因此它只是将所有32位移动到x
中。现在,x
的值为0xFFFFFFF4
,如果作为正数解释,则为4294967284
。但是printf
格式化字符串中的%d
表示要将32位视为有符号整数,所以结果是-12
。如果使用了%u
,则打印结果将为4294967284
。x
赋一个值,但不确定等号右侧的值是否为正数,你可以写unsigned int x = abs(-12);
,强制编译器在将有符号整数移动到无符号整数之前生成代码来取有符号整数的绝对值。unsigned int x = -12;
中,-12
是类型为int
的整数常量表达式。将其通过重复加(或减)UINT_MAX + 1
的值转换为unsigned int
,直到得到介于0和UINT_MAX
之间(包括两端)的值,该值是转换的结果。在反码或符号-数值机器上,这会改变值的位模式;而在更常见的二进制补码机器上,它只是相同位模式的不同解释。 - Daniel Fischerunsigned int x = -12;
之后,x
的值必须始终为 UINT_MAX - 11
。下一行的 printf("%d", x);
调用未定义的行为,因为 %d
转换说明符需要一个有符号的 int
,而 x
的值在 unsigned int
和 int
中都 不 可表示。通常的行为当然是重新解释位模式,在补码机器上,在这种情况下会产生 -11
,在带有32位 int
的原码和反码机器上,则为 -2147483636
。在二进制补码机器上则为观察到的行为。 - Daniel Fischerunsigned int
中该值小于UINT_MAX
的x
值无法表示? - ajayx
的值可以表示为 unsigned int
,但不能表示为 int
(除非实现方式很奇怪,其 unsigned int
具有填充位,因此范围是 int
范围的子范围)。使用 %d
转换说明符打印 unsigned int
是未定义行为,除非该值在两种类型中都可以表示。 - Daniel Fischer这个整数是无符号的,但你告诉printf
把它当作有符号整数来查看。
尝试使用
unsigned int x = -12; printf("%u", x);
它不会打印出"12",但会打印出无符号整数的最大值减去11。UINT_MAX-11
,而不是UINT_MAX-12
。 - R.. GitHub STOP HELPING ICE将%d传递给printf告诉printf将参数视为有符号整数,而不管您实际传递什么。使用%u以打印无符号整数。
printf('%d', x);
printf('%u', x);
它们确实存储正值。但是,由于您正在将(非常高的)正值输出为有符号整数,因此它会再次被重新解释(我可以补充说明,这是以一种实现定义的方式进行的)。
请改用格式标志"%u"
。
你的程序存在未定义行为,因为你向 printf
函数传递了错误的类型(你告诉它你要传递一个 int
类型,但实际上你传递了一个 unsigned int
类型)。幸运的是,实现中“最简单”的事情就是悄悄地打印错误的值而不跳转到某些有害的代码...
int和unsigned int用于分配一定数量的字节以存储一个值,仅此而已。
编译器应该会给出有关有符号不匹配的警告,但实际上并不影响表示值-12的内存中的位。
%x,%d,%u等告诉编译器在打印它们时如何解释一些位。
-12
转换为无符号数的结果为(UINT_MAX + 1) - 12
。 - pmg-Wsign-conversion
(包含在-Wconversion
中)可用于警告此问题。正如您现在所知,它不是-Wall
或-Wextra
的一部分。 - pmg-Wall
时会欺骗他们,因为它并没有打开所有的警告。 - user541686