Assigning long values

The limits of long type integers defined in the limits.h standard library header file are different in 32-bit and 64-bit modes, as shown in the following table.

Table 3. Constant limits of long integers in 32-bit and 64-bit modes
Symbolic constant Mode Value Hexadecimal Decimal
LONG_MIN (smallest signed long) 32-bit -(231) 0x80000000L -2,147,483,648
64-bit -(263) 0x8000000000000000L -9,223,372,036,854,775,808
LONG_MAX (longest signed long) 32-bit 231-1 0x7FFFFFFFL +2,147,483,647
64-bit 263-1 0x7FFFFFFFFFFFFFFFL +9,223,372,036,854,775,807
ULONG_MAX (longest unsigned long) 32-bit 232-1 0xFFFFFFFFUL +4,294,967,295
64-bit 264-1 0xFFFFFFFFFFFFFFFFUL +18,446,744,073,709,551,615

Implications of these differences are:

In situations where a long-type value can overflow when assigned to other variables or passed to functions, you must:

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.

Bit-shifting long values

Left-bit-shifting long values will produce different results in 32-bit and 64-bit modes. The examples in the table below show the effects of performing a bit-shift on long constants, using the following code segment:

long l=valueL<<1;
Table 5. Results of bit-shifting long values
Initial value Symbolic constant Value after bit shift
32-bit mode 64-bit mode
0x7FFFFFFFL INT_MAX 0xFFFFFFFE 0x00000000FFFFFFFE
0x80000000L INT_MIN 0x00000000 0x0000000100000000
0xFFFFFFFFL UINT_MAX 0xFFFFFFFE 0x1FFFFFFFE