| United States-English |
|
|
|
![]() |
HP-UX 64-bit Porting and Transition Guide: HP 9000 Computers > Chapter 4 Transitioning C and
aC++ Programs to 64-bit Mode Step 3: Make Source Code Changes |
|
If you are already using lint along with the HP C +w1 compile-line option, your port to the LP64 data model should be straightforward. When transitioning to 64-bit mode, strive to maintain a single set of source files and header files for both data models. Consider the following guidelines before porting to 64-bit mode:
Data can be truncated when longs are assigned to ints. To avoid this data truncation problem, change long to int assignments to assignments with the same data types. Example 4-1 Simple Assignment Truncation Before:
Solution: Decide if variable b must be long. If it must be long, make both variables long. Otherwise, make both variables int. Example 4-2 Bit Shift Truncation The following long to int assignment causes an overflow condition, which leads to unexpected results: Before:
The hex value for the base variable before the bit shift is:
The hex value of the intermediate result of the bit shift is:
This 64-bit intermediate result is truncated when assigned to final_result. The final_result is:
This code works in 32-bit mode since int and long are the same size. The code produces unexpected results in 64-bit mode since final_result is no longer big enough to hold the long value in base. Solution: To fix this code, make the variables final_result and base the same data type. Diagnostic Message: HP C generates the following LP64 migration warning for the above two examples when +M2 and +DD64 are enabled:
Data is promoted differently in 64-bit mode than in 32-bit mode when unsigned ints are compared to longs, and when ints are compared to unsigned longs. To avoid unintended data promotion problems, ANSI C programs should perform arithmetic operations and comparisons only when all operands are signed or when all operands are unsigned. Example 4-3 Comparison between Signed and Unsigned Numbers The following program yields different results in 32-bit mode and 64-bit mode: Before:
In 32-bit ANSI C mode, the long value of -1 is promoted to an unsigned 32-bit number, making it a large positive number. In 32-bit mode, this program prints:
In 64-bit ANSI C mode, both operands are promoted to signed 64-bit numbers. In 64-bit mode, this program prints:
HP C generates the following LP64 migration warning for this example when +M2 and +DD64 are enabled:
Solution: The code should be fixed so it produces consistent results in 32-bit and 64-bit mode. Either declare i as long:
or cast i to a long:
Pointers will be truncated in 64-bit mode if they are assigned to ints. To avoid truncation of pointers, store memory addresses in variables declared as pointers or declared with intptr_t (defined in <inttypes.h>). Store the differences between two pointers in variables declared with ptrdiff_t (defined in <stddef.h>). Before:
HP C generates the following LP64 migration warning for this example when +M2 and +DD64 are enabled:
Solution: The solution uses the intptr_t type definition. This construct is portable across 32-bit and 64-bit platforms.
The return value from function calls can be truncated if its data type is larger than or incompatible with the variable to which it is assigned. Be aware that the C compiler assumes that functions return a value of type int, unless the function is properly declared. To avoid truncation of function return values, use ANSI C function prototypes for user-defined functions and standard header files for C library functions. Example 4-4 Function Prototype Truncation In the following example, calculate_offset() returns the difference between two pointers. In 32-bit mode, the result can be assigned to an int or long. In 64-bit mode, the result must be assigned to a 64-bit long or ptrdiff_t, as defined in <stddef.h>. The size of a pointer type may vary from platform to platform and from mode to mode. Therefore, using ptrdiff_t protects your application from different pointer sizes. Before:
Diagnostic Message:
Solution: One solution is to replace the int return type defined in the function prototype and in calculate_offset() with the portable ptrdiff_t:
In 64-bit mode, this type definition is a long. Example 4-5 System Library Truncation of Return Values The C library function malloc() returns a pointer. In the following example, a function prototype is not defined for malloc(). This leads to a run-time abort because the pointer returned by malloc() is truncated to an int. Before:
At run time, this program aborts with a segmentation fault. Diagnostic Message: HP C generates the following LP64 migration warning for the above example when +M2 and +DD64 are enabled:
Solution: One way to fix this code is to include the <stdlib.h> header file, which contains the ANSI C function prototype and the K&R C function declaration for malloc():
At run time, this program now displays:
HP C no longer treats a structure passed by value the same as a structure passed by reference. When calling functions that expect a pointer to a structure, be sure to explicitly pass a pointer to the structure. Before:
Diagnostic Message: By default, lint provides the following warning for this example:
Solution:
The solution is to pass the address of struct a rather than the structure itself to foo(). Dereferencing pointers using the wrong data type can yield incorrect results. In ILP32, a long pointer can be used to dereference an int value, and an int pointer can be used to dereference a long value because both values are the same length and alignment. In 64-bit mode, if a long value is dereferenced using an int pointer, only the first 32 bits of the 64-bit value will be retrieved. Before:
At run time, this program prints the following result:
Both j and k point to the same address, 800003ffff8004f0. Since j is a pointer to an int, it only displays the first 4 bytes of the array, while k displays the entire 8 bytes as shown: Diagnostic Message: HP C generates the following LP64 migration warning for this example when +M2 and +DD64 are enabled:
Solution: The solution is to change j from an int pointer to a long pointer because the object of the pointer is an array of longs.
Casts made between pointers and ints will lead to unexpected results in 64-bit mode because pointers and ints are no longer the same size. The following program aborts because of pointer truncation that results from casting a pointer as an int and storing the results in a 32-bit variable:
HP C generates the following LP64 migration warning for this example when +M2 and +DD64 are enabled:
The default run time behavior changes for programs that use unqualified or unnamed bit fields in 64-bit mode. To avoid data alignment problems and unexpected results in programs that use bit fields, follow these guidelines:
Before:
In 32-bit mode, this program prints:
In 64-bit mode, this program prints:
Solution: The code should be fixed so it produces consistent results in 32-bit and 64-bit mode. In ANSI C, a portable solution is:
In K&R C, the solution is to name the bit fields, change the long variable to an int, and compile with the +sb signed bit field option. Programs that assign hardcoded numeric constants to longs in 32-bit mode may get different results in 64-bit mode if they assume a long is 32 bits. In 64-bit mode, this assumption is incorrect. To avoid setting incorrect bit mask and hexadecimal values, use pre-processor directives with the the __LP64__ predefined type to generate platform specific code. Or, consider using the complement (~) operator. Example 4-6 Using the __LP64__ Predefined Macro and Complement (~) Operator In the following example, the programmer wants to set all but the last 4 bits of the long value to 1. This code works in 32-bit mode. However, in 64-bit mode, it sets the leftmost 32 bits to 0, the next 28 bits to 1, and the last 4 bits to 0. Before:
Solution 1:
The solution ifdefs the long to the correct 64-bit value. Solution 2:
The solution uses the complement (~) operator to reverse each bit in the operand. The suffix L is required for the long value so that HP C uses the correct length for the constant. grep for hardcoded system constants that represent sizes of data types. Here are some common 32-bit system constants:
Instead of hardcoding values, use the macro values in include files, such as <limits.h> and <inttypes.h>. Examples of macros in <limits.h> include INT_MAX, LONG_MAX, and CHAR_BIT. See the man page for limits(5) for more information. A better solution is to use the sizeof() operator. Before:
Solution 1:
Solution 2:
Check for hardcoded values in bit shift operations. The following examples only get expected results in 32-bit mode because they all hardcode a shift range of 32 bits:
Solution:
Uses the portable LONG_BIT from <limits.h>. Before: Here is an example that turns on the high bit (signed or leftmost bit):
Solution 1:
Solution 2:
Check for hardcoded constants in programs that use the memory(3C) and string(3C) family of functions. Unfortunately, hardcoding constants is common when the following routines are used:
Before:
The pointer_buffer is a buffer of pointers. The malloc() function attempts to allocate enough space for this buffer. This code does not allocate enough space for pointer_buffer because the size of a pointer is 8 bytes in 64-bit mode. Silent data corruption or a core dump can happen when the upper bound of the buffer is reached. Diagnostic Message: None. Solution:
The sizeof(void *) operator replaces the hardcoding of the size of a pointer. When using varargs, stdarg, or variable argument interfaces such as printf(), you must ensure that the algorithms that use the variable parameters are consistent with the 64-bit data model. Before:
The d specifier prints a 32-bit integer. After:
The ld specifier prints a 64-bit integer in 64-mode and a 32-bit integer in 32-bit mode. Before:
The x specifier prints a 32-bit hexadecimal number. After:
The PRIx64 macro prints a 64-bit integer in both modes. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||