我有一个奇怪的错误/错误/自我愚蠢的问题。我正在用C语言开发一个小型应用程序,我使用的是Visual Studio 2010 SP1。违规代码:
uint64_t sum_squared_X = 65535*65535*64;
int64_t sum_squared_Y = 65535*65535*64;
在调试时,我得到以下结果:
sum_squared_X = 18446744073701163072;
sum_squared_Y = -8388544;
问题是,为什么?UIT64 64 T的最大值为2 ^ 64 -1或1844 67407370955 1615,最大值为2 ^ 63-1或922337203685477580。
65535×65535×64=274869518400,低于最大值。那为什么我会得到这些结果呢?
我在这里完全迷路了,请帮忙。
最佳答案
简而言之:65535乘以65535,使用32个大符号算术,得到-131071。然后将其乘以-64并转换为uint64_t(由于换行而产生更大的正值)或int64_t(保留-131071乘以64的结果)。
长答案:
非固定整数十进制常量的类型取决于其值。这个列表中的第一个可以表示它的值:int,long int,long long int(添加后缀或使用八进制或十六进制常量更改列表)。因为这些类型依赖于C实现,所以行为依赖于C实现。
在你的机器里,int可能是32位。因此,“65535”的类型是int,“64”的类型也是int。
表达式以“65535*65535”开头。这将65535乘以65535。数学结果是4924836225(十六进制,0xfffe0001)。对于32位带符号的int,这会溢出可表示的值。这是C标准中未定义的行为。在许多实现中,通常发生的情况是值“环绕”从231-1(最高可表示值)到-231(最低可表示值)。同一行为的另一种观点是,数学结果的位0xfffe0001被解释为32位有符号整数的编码。在two的补码中,0xfffe0001是-131071。
然后你的表达式乘以64。-131071*64不溢出;结果为-8388544(编码为0xff800040)。
最后,使用结果初始化uint64或int64对象。此初始化将导致转换为目标类型。
int64_t转换很简单;转换的输入是-8388544,这在int64_t中完全可以表示,因此结果是-8388544,编译器可能只是通过扩展符号位(生成编码0xffffffff800040)来实现。
UTIN 64转换是麻烦的,因为-8388544不能在UIT64 64 T中表示。根据1999 C标准,3.3.1.3 2,“通过重复添加或减去一个大于在新类型中可以表示的最大值,直到该值在新类型的范围内的值来转换该值。”“大于在新类型中可以表示的最大值”是264。所以结果是-8388544+264,即18446744073701163072。它还有编码0xffffffff800040。
为了从较窄的宽度转换为更宽的宽度,这种增加一个大于最大值的操作相当于将旧类型的符号位复制到新类型(符号扩展)中的所有高位。对于从较宽宽度到较窄宽度的转换,相当于丢弃高位。在这两种情况下,结果是剩余模2n,其中n是新类型中的位数。
关于c++ - Visual Studio 2010 SP1中的64位整数初始化错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11883001/