无符号和有符号的int和printf

时间:2014-11-30 03:08:15

标签: c++ c

据我所知,我为signed int分配的值大于它可以处理的值。此外,我应该使用%d进行签名,将%u用于无符号。同样,我不应该将-ve值分配给unsigned。但是如果我进行这样的分配并使用如下的printf,我会得到如下结果。

我的理解是,在每种情况下,转换为其两个恭维二进制表示的数量对于-14294967295是相同的。这就是为%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

2 个答案:

答案 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.