C++ unsigned long 在 4294967295 之后不会回绕
Posted
技术标签:
【中文标题】C++ unsigned long 在 4294967295 之后不会回绕【英文标题】:C++ unsigned long doesn't wrap around after 4294967295 【发布时间】:2015-06-07 17:43:25 【问题描述】:我在玩一些 c++ 代码,发现如果我用 4294967295(它的最大允许值)开始一个 unsigned long 并添加假设 6,我必须得到 5,它确实如此!但是下面的加法运算,mod 255并没有给出正确答案。为什么会发生这种情况,如何避免?
经过测试的平台: Windows 7,Visual Studio c++:工作正常; CentOS 6.6 版(最终版),g++:给出错误的答案; 请参阅代码下方的注释:
#include <stdio.h>
int main(int argc, char *argv[])
unsigned long s1=4294967295;
unsigned long vp=245;
unsigned long a;
unsigned long b;
unsigned long result;
/* s1 is 4294967295 + 6 wich is 5 */
s1+=6;
a=s1;
b=255*vp*s1;
result = (a + b) % 255;
printf("s1=%u , a=%u , b=%u , (a+b)=%u , (a+b)%255= %u\n", s1, a, b, a + b, result);
/* s1 is a static value 5 */
s1=5;
a=s1;
b=255*vp*s1;
result = (a + b) % 255;
printf("s1=%u , a=%u , b=%u , (a+b)=%u , (a+b)%255= %u\n", s1, a, b, a + b, result);
return 0;
注意: 如果我用 Visual Studio 编译代码,我会得到正确的答案。
s1=5 , a=5 , b=312375 , (a+b)=312380 , (a+b)%255= 5
s1=5 , a=5 , b=312375 , (a+b)=312380 , (a+b)%255= 5
但是,如果我使用 gcc 版本 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) 编译,我会得到:
s1=5 , a=5 , b=312375 , (a+b)=312380 , (a+b)%255= 6
s1=5 , a=5 , b=312375 , (a+b)=312380 , (a+b)%255= 5
在g++中如何避免?
【问题讨论】:
“如果我用 4294967295(他的最大允许值)开始一个无符号长整数”你从哪里读到的? 【参考方案1】:如果我用 4294967295(他的最大允许值)开始一个无符号长整数
如果unsigned long
是32 位类型,4294967295 只是unsigned long
的最大值。在 Windows 上就是这种情况,包括 32 位和 64 位。在 Linux 上,unsigned long
在 32 位平台上是 32 位类型,但在 64 位平台上是 64 位类型。 C++ 标准没有规定类型的特定大小,它只是说unsigned long
必须至少为 32 位,因此 Windows 和 Linux 都是正确的。
如果您想要有保证的 32 位类型,请使用来自 <cstdint>
的 uint32_t
(如果有)。它是该语言的最新添加,我不知道您的 Visual Studio 版本是否有它;如果没有,请参阅'uint32_t' identifier not found error。
另外,请注意您用于打印值的代码中存在错误。它碰巧不会在您尝试的两个平台上崩溃,但会截断 GCC 中的结果。要打印出unsigned long
,您需要使用%lu
说明符,而不是%u
。要打印出百分比字符,您需要将%
加倍。
printf("s1=%lu , a=%lu , b=%lu , (a+b)=%lu , (a+b)%%255= %lu\n", s1, a, b, a + b, result);
或者,由于您使用的是 C++,因此请使用其自己的打印机制。
#include <iostream>
…
std::cout << "s1=" << s1
<< ", a=" << a
<< ", b=" << b
<< ", (a+b)=" << (a+b)
<< ", (a+b)%255=" << result;
在unsigned long
是64位类型的平台上,s1
的第一次循环值为4294967301。b
的值为268328082129975。如果你使用正确的你会看到这些值打印说明符。
【讨论】:
uint32 可以找到 #include您使用的是 64 位系统吗?因为那时long
在 GCC 中通常是 64 位,而在 Visual Studio 编译器中仍然是 32 位,这将解释为什么它不适用于 GCC 但适用于 VS。
要获取某个类型的最大值,请使用`std::numeric_limits 获取,例如
unsigned long s1 = std::numeric_limits<unsigned long>::max();
【讨论】:
它打印 5 和 6 而不是一个大数字的事实可能是因为他们在printf()
中使用%u
而不是%lu
。
操作!。我知道了。我将类型更改为无符号整数,即 32 位。现在工作正常。一些编译器指令,谢谢。以上是关于C++ unsigned long 在 4294967295 之后不会回绕的主要内容,如果未能解决你的问题,请参考以下文章
带有 unsigned long long 和 sprintf 的 Visual C++ 6.0
JAVA 与 C++ 数据类型转换 byte unsigned char
C++ 指针(不论什么一个指针本身的类型都是unsigned long int型)
将 unsigned long long 转换为 wchar_t * 并连接