我为标题道歉,因为我不得不以某种方式找到一个独特的标题。
请考虑以下代码:
#include<stdio.h>
int main(void)
{
int b = 2147483648; // To show the maximum value of int type here is 2147483647
printf("%d\n",b);
unsigned int a = 2147483650;
unsigned int c = a+(-1);
printf("%u\n",c);
}
使用gcc编译器在64位操作系统上运行时,上述程序的输出为:
-2147483648
2147483649
请参阅我对此案的理解:
Unsigned int a超出了signed int类型的范围。在R.H.S(-1)中将转换为unsigned int,因为操作数是不同类型的。将-1转换为unsigned int的结果是:
-1 + (unsigned int MAX_UINT +1) = unsigned int MAX_UINT = 4294967295.
现在R.H.S将会:
unsigned int MAX_UINT + 2147483650
现在看起来它超出了unsigned int的范围。我不知道如何从这里开始,看起来即使我继续这个解释,我也不会达到经验输出。
请给出正确的解释。
PS:知道int b = 2147483648
成为-2147483648
的方式不是我的意图。我刚刚在代码中添加了该行,因此很清楚2147483650
超出int
范围。
答案 0 :(得分:3)
2147483648
不是32位int
,而是高于INT_MAX
,在此类平台上的值为2147483647
。
int b = 2147483648;
是实现定义的。在您的平台上,它似乎执行32位环绕,这是两种补充架构的典型,但不受C标准的保证。
因此printf("%d\n", b);
输出-2147483648
。
其余代码在32位系统上完美定义,输出2147483649
是正确且预期的。操作系统 64 bit 在评估步骤中起着非常微妙的作用,但实际上与C标准完全无关的实际结果无关。
以下是步骤:
unsigned int a = 2147483650;
这里不足为奇,a
是unsigned int
,其初始值设定项为int
,long int
或{{1取决于这些类型中的哪一个具有至少32个值位。在Windows和32位Linux上,它将是long long int
,而在64位Linux上,它将是long long int
。存储到long int
变量时,该值将被截断为32位。
您可以通过添加以下代码来验证这些步骤:
unsigned int
第二个定义printf("sizeof(2147483650) -> %d\n", (int)sizeof(2147483650));
printf(" sizeof(a) -> %d\n", (int)sizeof(a));
经历了相同的步骤:
unsigned int c = a+(-1);
被定义为c
,当存储到unsigned int
时,其初始化程序被截断为32位。初始化程序是一个补充:c
,其值为unsigned int
。2147483650U
的一元否定值为int
。因此,正确分析后,它是1
,其值为int
。-1
:转换以2 32 为模,因此值为unsigned int
。4294967295U
类型的宽度为模,因此结果为unsigned int
,其值为unsigned int
,({ {1}} modulo 2 32 )2147483649U
值存储在6442450945
中,并使用unsigned int
作为c
正确打印。如果表达式是printf("%u\n", c);
,则计算将在64位带符号的算术中进行,类型为2147483649
或2147483650 + (-1)
,具体取决于体系结构,结果为{ {1}}。当存储到long int
时,该值将被截断为32位,因此long long int
的值与2147483649
相同。
请注意,上述步骤不依赖于负值的实际表示。它们是针对所有体系结构完全定义的,只有类型c
的宽度很重要。
您可以使用额外代码验证这些步骤。这是一个完整的仪表程序来说明这些步骤:
c
输出:
2147483649
答案 1 :(得分:1)
int b = 2147483648;
printf("%d\n",b);
// -2147483648
转换一个超出目标签名类型范围的整数(任何有符号或无符号):
...结果是实现定义的,或者引发实现定义的信号。 C11§6.3.1.33
对于带符号整数2147483648的情况,实现定义的行为似乎将源2147483648
的最低32位映射到int
的32位。这可能不是另一个编译器的结果。
a+(-1)
与a + (-(1u))
相同,a + (-1u + UINT_MAX + 1u)
与a + UINT_MAX
相同。 添加溢出unsigned
范围,但无符号溢出包围。因此,在分配之前,总和为2147483649
。使用以下代码,不会超出范围转换。唯一的转化是signed 1
到unsigned 1
和long 2147483650
(或long long 2147483650
)到unsigned 2147483650
。两者都在范围转换中。
unsigned int a = 2147483650;
unsigned int c = a+(-1);
printf("%u\n",c);
// 2147483649
答案 2 :(得分:0)
像这样看
0xFFFFFFFF
0
来自哪里?好吧,0x00000000
是1
,如果从中减去0xFFFFFFFF
,则得{4},因为无符号算术被定义为“换行”。
或者进一步采用十进制版本,0 - 1
为UINT_MAX
,因为unsigned int
包装,总和也是如此。
your value 2147483650
UINT_MAX + 4294967295
----------
6442450945
modulo 2^32 % 4294967296
----------
2147483649