2017-08-24 41 views
1

据我所知,十进制和十六进制只是表示(比方说)int为什么我可以用十六进制表示一个大于MAXINT的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 

} 

由于我的言论表明,这两个十进制数的总和大于MAXINT大的数字。这个数字在打印成小数时溢出了(正如我所期望的那样),但是当以十六进制打印时,它看起来非常好。有趣的是,如果我继续添加到这个数字,并导致它再次溢出,它将返回正确表示十进制数字。十六进制数字总是正确的。

任何人都可以解释为什么这是这种情况。

TIA

+3

因为'%x'将数字作为** unsigned ** int处理。 – litelite

+2

'%x'是* unsigned *'int'的格式说明符。所以从技术上来说,使用它与不符合unsigned的符号是未定义的行为。 –

+0

那么我们首先称之为“更大”。 -1469994584也是无符号的 - 比INT_MAX大,并且还将十六进制结果与无符号进行比较。 – harold

回答

3

援引n1570(最新C11草案),§7.21.6.1P8

[...]
O,U,X,Xunsigned int参数被转换成无符号八进制(Ò),无符号十进制 (Ú),或无符号十六进制表示法(XX)[...]

因此,概括地说,你正在使用一个转换符为错误类型这里。其实,您签署的溢出是未定义的行为,但您的实现显然使用2的补负数和溢出导致环绕您的系统上,所以结果是完全一致表示作为正确无符号号。

如果您使用%u而不是%x,您将看到十进制记号中的相同数字。再次,这将是未定义行为的结果,即发生在您的系统上“正确”。总是避免签名溢出,结果允许为任何东西

+0

为了更容易理解@Felix Palmen写了什么 - https://ideone.com/TwTl6Z –

+0

因此,这是否意味着由于我的机器上的实现,十六进制表示是正确的“偶然”? – mbamber

+0

@mbamber是的。 **大多数**机器/实现的行为都是这样的,2的补码和环绕签名溢出是非常普遍的。但C不能保证,所以你不能在* portable *代码中做这样的事情。有些机器的结果会有所不同。 –