Overview

This document provides information for developing code that is portable between HP-UX 32-bit, 64-bit, and other UNIX systems. It includes using industry-standard header files and HP-UX extensions that isolate platform-specific code.

Making code 64-bit clean

Applications should be 64-bit clean if they are targeted for execution on both ILP32 and LP64. Tools to help make code 64-bit clean include:

using lint,

compiling in ANSI C or aC++, and

using the portable header file <inttypes.h>.

To make code 64-bit clean, follow these guidelines:

Use the same source code and header files for both 32-bit and 64-bit programs.

Use appropriate data types consistently and strictly.

For example, use off_t consistently for file offsets and fpos_t for file positions.

Use integral types in <inttypes.h>, where applicable, instead of int and long

Use fixed/scalable width integral types, algorithms, and masks as appropriate.

Fixed types remain a consistent size on 32-bit and 64-bit platforms. For example, use int32_t, defined in <inttypes.h>, if ints and longs should be 32 bits in your application. Scalable types can grow and scale without modification to future architectures.

Perform boundary checking on integral type ranges.

Update 64-bit code in cases where 32-bit and 64-bit processes share the same memory segment.

Using integral types defined in <inttypes.h>

The <inttypes.h> header files provide the following features that help you write portable code:

integral type definitions

macros for constants

macros for printf()/scanf() specifiers

When you use <inttypes.h>, you can maintain one set of source files for both data models. Using the typedefs and constants included in these header files protects your code from underlying data model changes. It also reduces the need to #ifdef platform-specific code, which improves the readability of your source code.

There are two <inttypes.h> header files. The following information is included in <sys/_inttypes.h>:

basic integral data types for 8, 16, 32, and 64 bits

macros that can create constants of a specific size and sign

The following information is included in <inttypes.h>:

data types for pointers

data types for the most efficient integer types

data types for the largest integer types

data types for the smallest integral types of at least 8, 16, 32, and 64 bits

Integer data types with consistent lengths

The basic types in <sys/_inttypes.h> have consistent lengths on UNIX 32-bit and 64-bit platforms. Use the basic data types in <sys/_inttypes.h>instead of the standard C language types whenever you want data types to remain the same size across different architectures.

This table shows the basic integral types in <sys/_inttypes.h>:

C basic integer Types

Type definition\name

Description

int8_t

8-bit signed integer

uint8_t

8-bit unsigned integer

int16_t

16-bit signed integer

uint16_t

16-bit unsigned integer

int32_t

32-bit signed integer

uint32_t

32-bit unsigned integer

int64_t

64-bit signed integer

uint64_t

64-bit unsigned integer

The pointer data types are signed and unsigned integer data types that are large enough to hold a pointer. A pointer can be moved to or from these data types without corruption.

Pointer types in Inttypes

Type definition\name

32-bit mode

64-bit mode

intptr_t

32-bit signed integer

64-bit signed integer

uintptr_t

32-bit unsigned integer

64-bit unsigned integer

Using integer data types with consistent lengths

One way to improve portability of programs that require integral data items to be 32-bits or 64-bits long, regardless of the hardware platform, is to include the <inttypes.h> header file, and to make the following substitutions:

Instead of

Use

short

int16_t

unsigned short

uint16_t

int

int32_t

unsigned int

uint32_t

long

int32_t or int64_t

unsigned long

uint32_t or unint64_t

long long

int64_t

unsigned long long

uint64_t

Excerpts from <inttypes.h> and <sys/_inttypes.h>

Here are some typedefs in <sys/_inttypes.h> that conform to the XPG5 standard:

The before code prints a 32-bit number on 32-bit platforms and a 64-bit number on a 64-bit platform. The after code prints a 32-bit number, regardless of the platform. The macro PRIx32 from <inttypes.h> is used instead of the literal x. PRIx32 is then defined as the appropriate formatting symbol.

int_fast data types with defined minimum sizes

When execution speed of programs is important, use the int_fastx_t data types in <sys/_inttypes.h>. You select data types based on the minimum integer size required by your application. The <inttype.h> header file then maps the int_fast data types to the fastest appropriate data type for the target hardware platform. These data types include:

intfast_t

fastest signed integral data type of at least 16-bits

int_fast8_t

fastest signed integral data type at least 8-bits long

uint_fast8_t

fastest unsigned integral data type at least 8-bits long

int_fast16_t

fastest signed integral data type at least 16-bits long

uint_fast16_t

fastest unsigned integral data type at least 16-bits long

int_fast32_t

fastest signed integral data type at least 32-bits long

uint_fast32_t

fastest unsigned integral data type at least 32-bits long

Example using int_fastn_t data types

Suppose you need a loop to execute as fast as possible on a target platform. You could change the following:

Guidelines for using <inttypes.h>

When porting to 64 bits, only use 64-bit data types when they are required. This data type may not be processed efficiently on some platforms. Programs may run slower and executable file sizes may be bigger.

Here are additional guidelines:

Use int32_t for integers that must be 32-bits in length on 64-bit systems in order for programs to work correctly. Because <inttypes.h> is available on both 32-bit and 64-bit HP-UX platforms, int32_t works in both environments.

Use the smallest integral type possible in order to control the size of the application.

Use the intfastn_t data types for counters and counter loops that need to be fast due to frequent expression evaluations (such as incrementing).

Use the constant that matches the integer type definition. For example, use the constant UINT64_MAX with uint_fast64_t. Do not use INT_MAX or UINT_MAX with uint_fast64_t.

Use intmax_t or uintmax_t for items that must be the largest available integral type as specified by the compiler. The sizes of these data types may change in a future release, but they will always be the largest integral type supported on the platform, regardless of possible performance implications.

Limit the use of x64_t data types. These types cannot automatically take advantage of potentially higher limits for future integral sizes as with intmax_t and uintmax_t.

Older 32-bit systems may not have a 64-bit integral data type. Therefore, int64_t and uint64_t data types may need to be protected by #ifdefs if the source code is shared between 64-bit and older 32-bit systems.

Convert long long to int64_t. Convert unsigned long long to uint64_t.

End user APIs reflect the data types defined by standards such as X/Open, POSIX.2, or legacy HP definitions. They will not cause source level incompatibilities. The function prototype looks the same in any integral data type model. Therefore, your application will be protected when there are changes to the underlying size of data types. For example, the function prototype for lseek():

Using portal.h

The <sys/portal.h> header file helps you to write code that is portable across HP-UX 32-bit and 64-bit systems. This header file contains macros for setting bit masks and sign bits of data types defined in <inttypes.h> and for convenience it includes the header files <limits.h> and <inttypes.h>.

To #include this header file, type:

#include <sys/portal.h>

Examples of some macros contained in portal.h follow:

SET_MASK_BIT(bit_num, data_type) -- Creates a mask that has one bit set.

For example:

SET_MASK_BIT(SIGN_BIT(int64_t), int64_t)

turns on the high bit in a 64-bit integer

SIGN_BIT (data_type)--Returns the bit position of the sign bit for the specified type.

Use fixed size masks with fixed size type definitions. For example, if you want a 32-bit mask use the portable construct:

#include <inttypes.h>int32_t intmask = INT32_MAX;

instead of:

long intmask = 0x7fffffff;

Using pstat(2) instead of /dev/kmem

Avoid writing programs that read system files such as /dev/kmem directly. These files may have different formats on different systems. Instead, use the pstat(2) routines to get system information. These routines were first introduced in the HP-UX 10.0 release. Using pstat(2), information can be retrieved about the following:

memory--static, dynamic, shared, virtual

system CPU processors

system processes and messaging

disks, swap space, and file systems

semaphores

NoteThe pstat(2) routines are HP-specific routines and are not available on other vendor platforms.

A wide (64 bit) version of the pstat(2) interfaces are available for narrow (32 bit) applications to use. A narrow application could use the flag -D_PSTAT64 at compile time to switch to the wide interfaces.

If the wide version is not used, the following pstat_get*(2) system calls may fail, with errno set to EOVERFLOW, when invoked within 32-bit applications. This is because within 64-bit HP-UX, many parameters, limits and addresses are 64-bit values and they cannot fit into fields of the corresponding struct pst_* data structure.

Additionally, confstr(3C) (configuration string) returns the appropriate compiler options, libraries, and lint options to build and check an application using a 32-bit or 64-bit programming environment.

Isolating system-specific code

Use conditional directives to isolate sections of platform or release-specific code. This is useful when the number of lines of release or platform-specific source code is small in relation to the number of lines of common code. You could, for example, encapsulate code that is different between the 32-bit and 64-bit HP-UX with conditional directives.

The following example uses a #define macro within a conditional directive: