首页 文章

无符号和有符号的int和printf

提问于
浏览
1

据我所知,我为signed int赋予了一个比它能处理的值更大的值 . 另外,我应该使用 %d 进行签名,将 %u 用于unsigned . 同样,我不应该将 -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 回答

  • 2

    这就是为什么%u签名打印4294967295忽略-ve leftmost bit . 当%d用于signed int时,它使用最左边的位作为-ve标志并打印-1 .

    在无符号的情况下,"leftmost"或最高有效位不被忽略,并且不是负数;相反,它的地方 Value 为231 .

    在否定的情况下,符号位不是标志;相反,它的位置值为-231 .

    在这两种情况下,整数的值等于设置为1的所有二进制数字(位)的位置值的总和 .

    以这种方式对带符号值进行编码称为two's complement . 它不是唯一可能的编码;你所描述的被称为符号和数量,例如,一个补充是另一种可能性 . 然而,这些替代编码在实践中很少遇到,尤其是因为两个补码是算术如何在现代硬件上工作,但可能是最神秘的架构 .

  • 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函数说:

    如果转换规范无效,则行为未定义.248)如果任何参数不是相应转换规范的正确类型,则行为未定义 .

    对于格式说明符, fprintf 涵盖 printf ,而对于 printf ,C则回退到C.

相关问题