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 2. 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:
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 3. 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.
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 4. 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 |