Go to main content

Oracle® Solaris 64-bit Developer's Guide

Exit Print View

Updated: March 2019
 
 

4.2 Implementing Single Source Code

The sections that follow describe some of the resources available to application developers that help you write single-source code that supports both 32-bit and 64-bit compilation.

The system include files sys/types.h and inttypes.h contain constants, macros, and derived types that are helpful in making applications 32-bit and 64-bit safe. While a detailed discussion of these is beyond the scope of this document, some are discussed in the sections that follow, and in Changes in Derived Types.

4.2.1 Feature Test Macros

An application source file that includes sys/types.h makes the definitions of the programming model symbols, _LP64 and _ILP32, available when you include sys/isa_defs.h.

For information about preprocessor symbols (_LP64 and _ILP32) and macros (_LITTLE_ENDIAN and _BIG_ENDIAN), see the types(3HEAD) man page.

4.2.2 Derived Types

Using the system derived types to make code safe for both the 32-bit and the 64-bit compilation environment is good programming practice. When you use derived data-types, only the system derived types must change for data model changes, or porting.

The system include files sys/types.h and inttypes.h contain constants, macros, and derived types that are helpful in making applications 32-bit and 64-bit safe.

4.2.3 sys/types.h Header File

Include sys/types.h in an application source file to gain access to the definition of _LP64 and _ILP32. This header also contains a number of basic derived types that should be used whenever appropriate. In particular, the following are of special interest:

  • clock_t represents the system times in clock ticks.

  • dev_t is used for device numbers.

  • off_t is used for file sizes and offsets.

  • ptrdiff_t is the signed integral type for the result of subtracting two pointers.

  • size_t reflects the size, in bytes, of objects in memory.

  • ssize_t is used by functions that return a count of bytes or an error indication.

  • time_t counts time in seconds.

All of these types remain 32-bit quantities in the ILP32 compilation environment and grow to 64-bit quantities in the LP64 compilation environment.

4.2.4 inttypes.h Header File

The inttypes.h include file was added to the Solaris 2.6 release to provide constants, macros, and derived types that help programmers make their code compatible with explicitly sized data items, independent of the compilation environment. It contains mechanisms for manipulating 8-bit, 16-bit, 32-bit, and 64-bit objects. The file contains the type definitions specified in the ISO C99 standard (ISO/IEC 9899:1999) for the C programming language.

    The basic features provided by inttypes.h are:

  • Fixed-width integer types.

  • Helpful types such as uintptr_t

  • Constant macros

  • Limits

  • Format string macros

The following sections provide more information about the basic features of <inttypes.h>.

4.2.4.1 Fixed-Width Integer Types

The fixed-width integer types that inttypes.h provides include signed integer types such as int8_t, int16_t, int32_t, and int64_t, and unsigned integer types such as uint8_t, uint16_t, uint32_t, and uint64_t.

Derived types, defined as the smallest integer types that can hold the specified number of bits, include int_least8_t,…, int_least64_t, uint_least8_t,…, uint_least64_t.

Using an int or unsigned int for such operations as loop counters and file descriptors is safe. Using a long for an array index is also safe. However, do not use these fixed-width types indiscriminately. Use fixed-width types for explicit binary representations of the following items:

  • On-disk data

  • Over the data wire

  • Hardware registers

  • Binary interface specifications

  • Binary data structures

4.2.4.2 Helpful Types Such as unintptr_t

The inttypes.h file includes signed and unsigned integer types large enough to hold a pointer. These are given as intptr_t and uintptr_t. In addition, inttypes.h provides intmax_t and uintmax_t, which are the longest (in bits) signed and unsigned integer types available.

Use the uintptr_t type as the integral type for pointers instead of a fundamental type such as unsigned long. Even though an unsigned long is the same size as a pointer in both the ILP32 and LP64 data models, using uintptr_t means that only the definition of uintptr_t is affected if the data model changes. This method makes your code portable to many other systems and is also a clearer way to express your intentions in C.

The intptr_t and uintptr_t types are extremely useful for casting pointers when you want to perform address arithmetic. Use intptr_t and uintptr_t types instead of long or unsigned long for this purpose.


Note -  Use of uintptr_t for casting is usually safer than intptr_t, especially for comparisons.

4.2.4.3 Constant Macros

Macros are provided to specify the size and sign of a given constant. The macros are INT8_C(c), ..., INT64_C(c), UINT8_C(c),..., UINT64_C(c). Basically, these macros place an l, ul, ll, or ull at the end of the constant, if necessary. For example, INT64_C(2) appends ll to the constant 2 for ILP32 and an l for LP64.

Macros for making a constant the biggest type are INTMAX_C(c) and UINTMAX_C(c). These macros can be very useful for specifying the type of constants described in Guidelines for Converting to LP64 Data Type Model.

4.2.4.4 Limits in inttypes.h

The limits defined by inttypes.h are constants specifying the minimum and maximum values of various integer types. This includes minimum and maximum values of each of the fixed-width types, such as INT8_MIN,..., INT64_MIN, INT8_MAX,..., INT64_MAX, and their unsigned counterparts.

The minimum and maximum for each of the least-sized types are given, too. These include INT_LEAST8_MIN,..., INT_LEAST64_MIN, INT_LEAST8_MAX,..., INT_LEAST64_MAX, and their unsigned counterparts.

Finally, the minimum and maximum value of the largest supported integer types is defined. These include INTMAX_MIN and INTMAX_MAX and their corresponding unsigned versions.

For more information, see the inttypes.h(3HEAD) man page.

4.2.4.5 Format String Macros

The inttypes.h file includes the macros that specify the printf() and scanf() format specifiers. Essentially, these macros prepend the format specifier with an l or ll to identify the argument as a long or long long, given that the number of bits in the argument is built into the name of the macro.

Some macros for printf(3C) print both the smallest and largest integer types in decimal, octal, unsigned, and hexadecimal formats, as shown in the following example.

int64_t i;
printf("i =%" PRIx64 "\n", i);

Similarly, macros for scanf(3C) read both the smallest and largest integer types in decimal, octal, unsigned, and hexadecimal formats.

uint64_t u;
scanf("%" SCNu64 "\n", &u);

Do not use these macros indiscriminately. They are best used in conjunction with the fixed-width types. For more information, see Fixed-Width Integer Types.