C++ unsigned long 在 4294967295 之后不回绕
C++ unsigned long doesn't wrap around after 4294967295
我正在玩一些 C++ 代码,发现如果我以 4294967295(它的最大允许值)开始一个 unsigned long 并添加比方说 6 我必须得到 5,而且确实如此!但是下面的加法运算,mod255并没有给出正确答案。为什么会发生这种情况,如何避免?
测试的平台:
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++ 中避免它?
您使用的是 64 位系统吗?因为 long
在 GCC 中通常是 64 位,而在 Visual Studio 编译器中它仍然是 32 位,这将解释为什么它不适用于 GCC 而适用于 VS。
要获取某个类型的最大值,请使用`std::numeric_limits获取它,例如
unsigned long s1 = std::numeric_limits<unsigned long>::max();
if i start a unsigned long with 4294967295 ( his max allowed value )
如果 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。你会如果您使用正确的打印说明符,请查看这些值。
我正在玩一些 C++ 代码,发现如果我以 4294967295(它的最大允许值)开始一个 unsigned long 并添加比方说 6 我必须得到 5,而且确实如此!但是下面的加法运算,mod255并没有给出正确答案。为什么会发生这种情况,如何避免?
测试的平台:
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++ 中避免它?
您使用的是 64 位系统吗?因为 long
在 GCC 中通常是 64 位,而在 Visual Studio 编译器中它仍然是 32 位,这将解释为什么它不适用于 GCC 而适用于 VS。
要获取某个类型的最大值,请使用`std::numeric_limits获取它,例如
unsigned long s1 = std::numeric_limits<unsigned long>::max();
如果if i start a unsigned long with 4294967295 ( his max allowed value )
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。你会如果您使用正确的打印说明符,请查看这些值。