Ham*_*ani 25 c++ multiplication uint64
我在c ++下编程时遇到了一件奇怪的事情.这是一个简单的乘法.
码:
unsigned __int64 a1 = 255*256*256*256;
unsigned __int64 a2= 255 << 24; // same as the above
cerr()<<"a1 is:"<<a1;
cerr()<<"a2 is:"<<a2;
Run Code Online (Sandbox Code Playgroud)
有趣的是结果是:
a1 is: 18446744073692774400
a2 is: 18446744073692774400
Run Code Online (Sandbox Code Playgroud)
而它应该是:(使用计算器确认)
4278190080
Run Code Online (Sandbox Code Playgroud)
谁能告诉我怎么可能呢?
oua*_*uah 39
255*256*256*256
Run Code Online (Sandbox Code Playgroud)
所有的操作数都是int你满溢的int.有符号整数的溢出是C和C++中未定义的行为.
编辑:
请注意,255 << 24如果您的int类型是,则第二个声明中的表达式也会调用未定义的行为32-bit.255 x (2^24)是4278190080不能用a表示的32-bit int(最大值通常2147483647在32-bit int二进制补码表示中).
C和C++都表示E1 << E2,如果E1是有符号类型且为正且E1 x (2^E2)无法在类型中表示E1,则程序将调用未定义的行为.这^是数学幂运算符.
Pup*_*ppy 17
你的文字是int.这意味着所有操作都实际执行int,并立即溢出.转换为无符号64位int时,此溢出值是您观察到的值.
zwo*_*wol 16
或许有必要解释生成数字18446744073692774400的情况.从技术上讲,您编写的表达式会触发"未定义的行为",因此编译器可能会产生任何结果; 但是,假设int是32位类型,现在几乎总是如此,如果你写的话,你会得到相同的"错误"答案
uint64_t x = (int) (255u*256u*256u*256u);
Run Code Online (Sandbox Code Playgroud)
那表情也没有引发未定义行为.(从转换unsigned int到int涉及实现定义的行为,但由于没有人在多年内产生一个补码或符号和大小的CPU,你可能遇到的所有实现都以完全相同的方式定义它.)我写了用C风格演员,因为我在这里说的一切同样适用于C和C++.
首先,让我们来看看乘法.我正在以十六进制编写右侧,因为它更容易看到正在发生的事情.
255u * 256u = 0x0000FF00u
255u * 256u * 256u = 0x00FF0000u
255u * 256u * 256u * 256u = 0xFF000000u (= 4278190080)
Run Code Online (Sandbox Code Playgroud)
最后一个结果,0xFF000000u具有32位数字集的最高位.因此,将该值转换为带符号的 32位类型会导致它变为负数 - 如果从中减去了32 32(这是我上面提到的实现定义的操作).
(int) (255u*256u*256u*256u) = 0xFF000000 = -16777216
Run Code Online (Sandbox Code Playgroud)
我在那里写了十六进制数,没有u后缀,以强调当你将它转换为有符号类型时,值的位模式不会改变; 它只是重新诠释.
现在,当您将-16777216分配给uint64_t变量时,通过添加2 64将其反转换为无符号as-if .(与无符号到符号的转换不同,此语义由标准规定.)这确实改变了位模式,将数字的所有高32位设置为1而不是0,如您所料:
(uint64_t) (int) (255u*256u*256u*256u) = 0xFFFFFFFFFF000000u
Run Code Online (Sandbox Code Playgroud)
如果你用0xFFFFFFFFFF000000十进制写,你会得到18446744073692774400.
作为最后的建议,每当你从C或C++得到一个"不可能"的整数时,尝试用十六进制打印出来; 通过这种方式更容易看到二进制补码固定宽度算术的奇怪之处.
| 归档时间: |
|
| 查看次数: |
2751 次 |
| 最近记录: |