Although type identification of constants follows explicit rules in C and C++, many programs use hexadecimal or unsuffixed constants as "typeless" variables and rely on a two's complement representation to exceed the limits permitted on a 32-bit system. As these large values are likely to be extended into a 64-bit long type in 64-bit mode, unexpected results can occur, generally at boundary areas such as:
Some examples of unexpected boundary side effects are listed in the following table.
Constant assigned to long | Equivalent value | 32 bit mode | 64 bit mode |
---|---|---|---|
-2,147,483,649 | INT_MIN-1 | +2,147,483,647 | -2,147,483,649 |
+2,147,483,648 | INT_MAX+1 | -2,147,483,648 | +2,147,483,648 |
+4,294,967,726 | UINT_MAX+1 | 0 | +4,294,967,296 |
0xFFFFFFFF | UINT_MAX | -1 | +4,294,967,295 |
0x100000000 | UINT_MAX+1 | 0 | +4,294,967,296 |
0xFFFFFFFFFFFFFFFF | ULONG_MAX | -1 | -1 |
Unsuffixed constants can lead to type ambiguities that can affect other parts of your program, such as when the results of sizeof operations are assigned to variables. For example, in 32-bit mode, the compiler types a number like 4294967295 (UINT_MAX) as an unsigned long and sizeof returns 4 bytes. In 64-bit mode, this same number becomes a signed long and sizeof will return 8 bytes. Similar problems occur when passing constants directly to functions.
You can avoid these problems by using the suffixes L (for long constants) or UL (for unsigned long constants) to explicitly type all constants that have the potential of affecting assignment or expression evaluation in other parts of your program. In the example cited above, suffixing the number as 4294967295U forces the compiler to always recognize the constant as an unsigned int in 32-bit or 64-bit mode.