据我所知,我为signed int分配的值大于它可以处理的值。此外,我应该使用%d
进行签名,将%u
用于无符号。同样,我不应该将-ve
值分配给unsigned。但是如果我进行这样的分配并使用如下的printf,我会得到如下结果。
我的理解是,在每种情况下,转换为其两个恭维二进制表示的数量对于-1
或4294967295
是相同的。这就是为%u
签名打印4294967295
而忽略最左边的-ve
位的原因。当%d用于signed int时,它使用最左边的位作为-ve
标志并打印-1
。同样,对于无符号的%u
打印无符号值,但%d
会使其将数字视为已签名,从而打印-1
。这是对的吗?
signed int si = 4294967295;
unsigned int ui = 4294967295;
printf("si = u=%u d=%d\n", si, si);
printf("ui = u=%u d=%d\n", ui, ui);
输出:
si = u=4294967295 d=-1
ui = u=4294967295 d=-1
signed int si = -1;
unsigned int ui = -1;
printf("si = u=%u d=%d\n", si, si);
printf("ui = u=%u d=%d\n", ui, ui);
输出:
si = u=4294967295 d=-1
ui = u=4294967295 d=-1
答案 0 :(得分:2)
这就是%u for signed通过忽略-ve leftmost bit打印4294967295的原因。当%d用于signed int时,它使用最左边的位作为-ve标志并打印-1。
在无符号的情况下,“最左边”或最高有效位不被忽略,并且不是负数;而它的位值为2 31 。
在否定的情况下,符号位不是标志;相反,它的位置值为-2 31 。
在这两种情况下,整数的值等于设置为1的所有二进制数字(位)的位值之和。
以这种方式对签名值进行编码称为 two's complement 。它不是唯一可能的编码;你所描述的被称为 sign and magnitude ,例如, one的补充是另一种可能性。然而,这些替代编码在实践中很少遇到,尤其是因为两个补码是算术如何在现代硬件中运行,但可能是最神秘的架构。
答案 1 :(得分:1)
这里有一些事情让我们开始说,使用不正确的格式说明符printf
是未定义的行为,这意味着你的程序结果是不可预测的,实际发生的将取决于许多因素,包括您的编译器,架构,优化级别等......
对于由相应标准定义的有符号/无符号转换,C和C ++都使其实现定义的行为,以转换大于存储在有符号整数类型中的值,来自C ++草案标准:
如果目标类型已签名,则该值不会更改,如果它可以在目标类型中表示(和 位域宽度);否则,该值是实现定义的。
例如gcc
选择使用相同的convention as unsigned:
为了转换为宽度为N的类型,将该值减去模2 ^ N以在该类型的范围内;没有信号被提出。
当您在C和C ++中将-1
分配给无符号值时,结果将始终是该类型的最大无符号值,来自草案C ++标准:
如果目标类型是无符号的,则结果值最小 无符号整数与源整数一致(模2n,其中n是 用于表示无符号类型的位数)。 [注意:在 两个补码表示,这种转换是概念性的 位模式没有变化(如果没有截断)。 - 后注]
C99的措辞更容易理解:
否则,如果新类型是无符号的,则转换为 重复加或减一个以上的最大值 可以用新类型表示,直到值在范围内 新类型。
所以我们有以下内容:
-1 + (UNSIGNED_MAX + 1)
结果为UNSIGNED_MAX
对于printf
和不正确的格式说明符,我们可以看到草案C99标准部分7.19.6.1
fprintf函数表示:
如果转换规范无效,则行为为 undefined .248)如果任何参数不是正确的类型 相应的转换规范,行为未定义。
fprintf
涵盖printf
格式说明符,C ++相对于printf
回退到C.