基本上当我这样做时,32位系统会发生什么:
uint32_t test (void)
{
uint32_t myInt;
myInt = ((0xFFFFFFFF * 0xFFFFFFFF) % 256u );
return myInt;
}
答案 0 :(得分:11)
我们假设int
是32位。
0xFFFFFFFF
的类型为unsigned int
。有一些特殊的规则可以解释这一点,但因为它是一个十六进制常量并且它不适合int
,但它适合unsigned int
,它最终为unsigned int
。
0xFFFFFFFF * 0xFFFFFFFF
将首先进行通常的算术转换,但由于双方都是unsigned int
,所以没有任何反应。乘法的结果是0xfffffffe00000001
,通过使用模2 32 值减少到unsigned int
,得到值为unsigned int
的值。
(unsigned int)1 % 256u
等于1
且类型为unsigned int
。通常的算术转换也适用于此,但同样,两个操作数都是unsigned int
,所以没有任何反应。
结果转换为uint32_t
,但它已经unsigned int
具有相同的范围。
然而,让我们假设int
是64位。
0xFFFFFFFF
的类型为int
。
0xFFFFFFFF * 0xFFFFFFFF
会溢出!这是未定义的行为。在这一点上,我们不再试图弄清楚程序的作用,因为它可以做任何事情。也许编译器决定不为这个函数发出代码,或者同样荒谬的东西。
这将发生在所谓的" ILP64"或" SILP64"建筑。这些架构很少见,但它们确实存在。我们可以使用0xFFFFFFFFu
来避免这些可移植性问题。
答案 1 :(得分:0)
无符号整数溢出意味着您可以尝试将一个值设置为大于它可以容纳的范围 - 但它将换行并将一个模数UINT32_MAX+1
。事实上,在这种情况下,如果您使用整数文字附加U
或u
,也会发生。否则整数文字被认为是,当结果是签名时(因为你没有指定任何东西),将导致由于乘法和有符号整数溢出而导致溢出,这是未定义的行为。
再次回到解释,这里当你将它相乘时(确保它们是无符号的(结果)将通过包裹在UINT32_MAX+1
中包裹它意味着如果它大于{{1}然后结果将应用于uint32_t
模数,然后我们使用UINT32_MAX
进行模运算,然后将结果存储在256u
中并从方法返回。 (注意,如果溢出的乘法结果将首先作为uint32_t
的模数)