I was playing with some c++ code, and found that if I start a unsigned long with 4294967295 (its max allowed value) and add let's say 6 I MUST get 5, and it does! but the following operation of addition, and mod 255 does not give the correct answer. why this happens, and how it can be avoided?
Plataforms Tested:
Windows 7, Visual Studio c++ : Works Fine;
CentOS release 6.6 (Final), g++ : Give The Wrong Answer;
See NOTE below the code:
#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;
}
NOTE: if I compile the code with Visual Studio, I get the correct answer.
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
BUT, if I compile with gcc version 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) I get:
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
How it can be avoided in g++?
4294967295 is only the maximum value for
unsigned long
ifunsigned long
is a 32-bit type. This is the case on Windows, both 32-bit and 64-bit. On Linux,unsigned long
is a 32-bit type on 32-bit platforms but a 64-bit type on 64-bit platforms. The C++ standard doesn't mandate a particular size for types, it only says thatunsigned long
must be at least 32 bits, so both Windows and Linux are correct.If you want a guaranteed 32-bit type, use
uint32_t
from<cstdint>
if available. It's a recent addition to the language, I don't know if your version of Visual Studio has it yet; if it doesn't, see 'uint32_t' identifier not found error.Also, beware that there are bugs in the code you're using to print out the values. It happens to not crash on the two platforms where you tried, but it truncates the result in GCC. To print out an
unsigned long
, you need to use the%lu
specifier, not%u
. To print out a percent character, you need to double the%
.Or alternatively, since you're using C++, use its own printing mechanism.
On a platform where
unsigned long
is a 64-bit type, the value ofs1
the first time round is 4294967301. The value ofb
is 268328082129975. You'll see these values if you use the correct printing specifiers.