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。你会如果您使用正确的打印说明符,请查看这些值。