Assigning constant values to long variables

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.

Table 4. Unexpected boundary results of constants assigned to long types
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.