|< Day Day Up >|
Section VI: Extended Integer Types
As described in Chapter 3, "Data and C," the C99 header file inttypes.h provides a systematic set of alternative names for the various integer types. These names describe the properties of the type more clearly than do the standard names. For example, type int might be 16 bits, 32 bits, or 64 bits, but the int32_t type always is 32 bits.
More precisely, the inttypes.h header file defines macros that can be used with scanf() and printf() to read and write integers of these types. This header file includes the stdlib.h header file, which provides the actual type definitions. The formatting macros are strings that can be concatenated with other strings to produce the proper formatting directions.
The types are defined using typedef. For example, a system with a 32-bit int might use this definition:
typedef int int32_t;
The format specifiers are defined using the #define directive. For example, a system using the previous definition for int32_t might have this definition:
#define PRId32 "d" // output specifier #define SCNd32 "d" // input specifier
Using these definitions, you could declare an extended integer variable, input a value, and display it as follows:
int32_t cd_sales; // 32-bit integer scanf("%" SCNd32, &cd_sales); printf("CD sales = %10" PRId32 " units\n", cd_sales);
String concatenation then combines strings, if needed, to get the final control string. Thus, the previous code gets converted to the following:
int cd_sales; // 32-bit integer scanf("%d", &cd_sales); printf("CD sales = %10d units\n", cd_sales);
If you moved the original code to a system with a 16-bit int, that system might define int32_t as long, PRId32 as "ld", and SCNd32 as "ld". But you could use the same code, knowing that it uses a 32-bit integer.
One set of typedefs identify types with precise sizes. The general form is intN_t for signed types and uintN_t for unsigned types, with N indicating the number of bits. Note, however, that not all systems can support all the types. For example, there could be a system for which the smallest usable memory size is 16 bits; such a system would not support the int8_t and uint8_t types. The format macros can use either d or i for the signed types, so PRIi8 and SCNi8 also work. For the unsigned types, you can substitute o, x, or X for u to obtain the %o , %x, or %X specifier instead of %u. For example, you can use PRIX32 to print a uint32_t type value in hexadecimal format. Table RS.VI.1 lists the exact-width types, format specifiers, and value limits.
The minimum-width types guarantee a type that is at least a certain number of bits in size. These types always exist. For example, a system that does not support 8-bit units could define int_least_8 as a 16-bit type. Table RS.VI.2 lists minimum-width types, format specifiers, and value limits.
Fastest Minimum-Width Types
For a particular system, some integer representations can be faster than others. For example, int_least16_t might be implemented as short, but the system might do arithmetic faster using type int. So inttypes.h also defines the fastest type for representing at least a certain number of bits. These types always exist. In some cases, there might be no clear-cut choice for fastest; in that case, the system simply specifies one of the choices. Table RS.VI.3 lists fastest minimum-width types, format specifiers, and value limits.
Sometimes you may want the largest integer type available. Table RS.VI.4 lists these types. They may, in fact, be wider than long long or unsigned long long, because a system may provide additional types wider than the required types.
Integers That Can Hold Pointer Values
The inttypes.h header file (via the included stdint.h header file) defines two integer types, listed in Table RS.VI.5, that can hold pointer values accurately. That is, if you assign a type void * value to one of these types, and then assign the integer type back to the pointer, no information is lost. Either or both types might not exist.
Extended Integer Constants
You can indicate a long constant with the L suffix, as in 445566L. How do you indicate that a constant is type int32_t? Use macros defined in inttypes.h. For example, the expression INT32_C(445566) expands to a type int32_t constant. Essentially, the macro is a type cast to the underlying type—that is, to the fundamental type that represents int32_t in a particular implementation.
The macro names are formed by taking the type name, replacing the _t with _C, and making all the letters uppercase. For example, to make 1000 a type uint_least64_t constant, use the expression UINT_LEAST64_C(1000).
|< Day Day Up >|