【问题标题】:Why can I represent an int larger than MAXINT in hexadecimal, but not decimal?为什么我可以用十六进制而不是十进制表示大于 MAXINT 的 int?
【发布时间】:2018-02-02 14:02:00
【问题描述】:

据我所知,十进制和十六进制只是(比如说)int 的表示。

这意味着如果我定义一个整数,x 我应该能够将x 打印为:

  • 小数点:printf("%d", x);
  • 十六进制:printf("%x", x);

我不明白当x 超过 MAXINT 时它的行为如何。

以下面的代码为例:

#include<stdio.h>

int main(int argc, char** argv) {

    // Define two numbers that are both less than MAXINT
    int a =  808548400;
    int b = 2016424312;

    int theSum = a + b; // 2824972712 -> larger than MAXINT

    printf("%d\n", theSum); // -1469994584 -> Overflowed
    printf("%x\n", theSum); // A861A9A8 -> Correct representation

}

正如我的 cmets 所建议的,这两个十进制数之和是一个大于 MAXINT 的数字。这个数字在打印为十进制时溢出(正如我所料),但当打印为十六进制时,它似乎完全没问题。

有趣的是,如果我继续添加这个数字,并导致它再次溢出,它会返回正确表示十进制数。十六进制数总是正确的。

谁能解释一下为什么会这样。

TIA

【问题讨论】:

  • 因为%x 将数字处理为 unsigned int。
  • %xunsigned int 的格式说明符。所以从技术上讲,将它与不适合无符号的有符号一起使用是未定义的行为。
  • 我们首先将什么叫做“更大”。 -1469994584 也是无符号的,大于 INT_MAX 并且您还比较了十六进制结果,就好像无符号一样。
  • 我希望有人写一个完整的答案而不是 cmets。 OP已经很困惑了;短的 cmets 只会让它更加混乱。
  • 很公平。同意。

标签: c int hex decimal


【解决方案1】:

引用 n1570(最新 C11 草案),§7.21.6.1 p8

[...]
o,u,x,X unsigned int 参数转换为无符号八进制 (o),无符号 十进制 (u) 或无符号十六进制表示法 (xX) [...]

因此,简而言之,您在这里使用了错误类型的转换说明符。实际上,您的签名溢出是未定义的行为,但您的实现显然对负数使用了 2 的补码,并且溢出会在您的系统上导致 环绕,因此结果正是与正确的无符号数字相同的表示。

如果您使用%u 而不是%x,您会看到相同的十进制数字。同样,这将是碰巧在您的系统上“正确”的未定义行为的结果。始终避免有符号溢出,结果可以是任何东西

【讨论】:

  • 那么这是否意味着由于我的机器上的实现,十六进制表示是“偶然”正确的?
  • @mbamber 是的。 大多数 机器/实现都以这种方式运行,符号溢出时的 2 补码和环绕是非常常见的。但是 C 不能保证这一点,所以你不能在 portable 代码中做这样的事情。有些机器的结果会有所不同。
猜你喜欢
  • 2014-10-27
  • 1970-01-01
  • 2015-02-05
  • 2013-03-31
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 2011-07-02
相关资源
最近更新 更多