stdint.h

From Wikipedia, the free encyclopedia

C Standard Library headers

stdint.h is a header file in the C standard library introduced in the C99 standard library section 7.18 to allow programmers to write more portable code by providing a set of typedefs that specify exact-width integer types, together with the defined minimum and maximum allowable values for each type, using macros. This header is particularly useful for embedded programming which often involves considerable manipulation of hardware specific I/O registers requiring integer data of fixed widths, specific locations and exact alignments. Both C and C++ developers should know that it is important to update their coding standards even if the compiler is not C99 compliant because a version of stdint.h (for C), and a version of stdint.h and cstdint (for C++) can be downloaded or quickly created. Care should be taken because the wrong version of the header will mean that types do not match reality.

The naming convention for exact-width integer types is intN_t for signed integers and uintN_t for unsigned integers. For example int8_t and uint64_t amongst others could be declared together with defining their corresponding ranges INT8_MIN to INT8_MAX and 0 (zero) to UINT64_MAX; again using a similar but uppercase naming convention. In addition stdint.h defines limits of integer types capable of holding object pointers such as UINTPTR_MAX, the value of which depends on the processor and its address range.

The exact-width types and their corresponding ranges are only included in that header if they exist for that specific compiler/processor. Note that even on the same processor, two different compiler implementations can differ. The use of #if or #ifdef would allow the inclusion or exclusion of types by the use of compilers preprocessor so that the correct exact-width set is selected for a compiler and its processor target.

Contents

[edit] Coding Standards for C and C++

This 1999 update to the International Organization for Standardization's (ISO) was signed off fully in 2004. Its importance can not be ignored because it clearly adds something that was missing from C and C++ but which developers naturally had a solution even if it was partial and varied from project to project. This however makes it clear and unambiguous, increases code portability and makes compile time error checking more consistent - particularly for embedded developers. Most significantly software designers and system architects can refer to these data types and ranges by name - unambiguously.

Both C and C++ developers can add #include <stdint.h> to their source code to obtain this important part of the standard, which they can do even if their compiler is not C99 compliant. This does not mean to say that types already used in a project like uint16 and byte should all be changed, only that the use of this standard is preferable for all code changes and essential for new projects. If the code is intended for publication as open source then the standard is more strongly recommended.

[edit] Specific coding Standards for C++ developers

The use of <stdint.h> puts the contents into the global namespace, and since global namespace contains namespace std it is in namespace std too which is a reasonable thing to do. If your compiler has <cstdint> and you use this instead, then the types are part of namespace std only. Either refer to them fully as std::int8_t for example or use using namespace std; with the the shorter method int8_t.

[edit] Background

[edit] Corresponding integer types

The C standard has a notion of "corresponding integer types". Informally, what this means is for any integer type T:

typedef   signed T A;
typedef unsigned T B;

the type A and the type B are said to be corresponding integer types (note: typedef doesn't create a new type, it creates a new identifier as a synonym for the given type). This is important for two reasons:

  • corresponding types are friendly to aliasing and type puns
  • corresponding types have a similar object representation

Both of these combined require code like:

A a = 1;
B b = 1;
*(B*)&a = 0;
*(A*)&b = 0;

to have defined behavior by the standard (as opposed to being undefined in the general case). There are many caveats to how far you can push this, so it's important to actually read the C standard to see what's legal or not (the bulk of this has to deal with padding bits and out of range representations).

[edit] Representation

The C99 standard elaborated the difference between value representations and object representations.

The object representation of an integer consists of 0 or more padding bits, 1 or more value bits[1], and either 0 or 1 sign bits (this doesn't count as a value bit) depending on the signedness of the integer type.

The value representation is a conceptual representation of an integer. The value representation ignores any padding bits and does a (possible) rearrangement to the bits so that the integer is ordered sequentially from most significant value bit to least significant value bit. Most programmers deal with this representation because it allows them easily write portable code by only dealing with -0 and out of range values as opposed to both of those in addition to tricky aliasing rules and trap representations if they choose to deal with the object representation directly.


[edit] Signed representation

The C standard allows for only three signed integer representations:

[edit] New integer types

  • The types <something>_t and u<something>_t are required to be corresponding integer types.
  • For the types that are marked optional, an implementation must either define both <something>_t and u<something>_t or neither of the two.
  • If a type is of the form [u]<something>N_t (or similarly for a preprocessor define), N must be a positive decimal integer with no leading 0's.

[edit] Exact-width integer types (optional)

These are of the form intN_t and uintN_t.

  • Both types must have no padding bits.
  • intN_t must be encoded as a two's complement signed integer.

An implementation is required to define exact-width integer types for N = 8[2], 16, 32, or 64 if and only if it has any type that meets the requirements. It is not required to define them for any other N, even if it supports the appropriate types.

Specific integral type limits
Specifier Common Equivalent Signing Bits Bytes Minimum Value Maximum Value
int8_t signed char Signed 8 1 −128 127
uint8_t unsigned char Unsigned 8 1 0 255
int16_t short Signed 16 2 −32,768 32,767
uint16_t unsigned short Unsigned 16 2 0 65,535
int32_t long Signed 32 4 −2,147,483,648 2,147,483,647
uint32_t unsigned long Unsigned 32 4 0 4,294,967,295
int64_t long long Signed 64 8 −9,223,372,036,854,775,808 9,223,372,036,854,775,807
uint64_t unsigned long long Unsigned 64 8 0 18,446,744,073,709,551,615

[edit] Minimum-width integer types

These are of the form int_leastN_t and uint_leastN_t.

The standard doesn't mandate anything about these types except that their widths must be ≥ N.

An implementation is required to define these for the following N: 8, 16, 32, 64.

  • INT_LEASTN_MIN
  • INT_LEASTN_MAX
  • UINT_LEASTN_MAX
  • INTN_C(value)
  • UINTN_C(value)

[edit] Fastest minimum-width integer types

These are of the form int_fastN_t and uint_fastN_t.

The standard doesn't mandate anything about these types except that their widths must be ≥ N. It also leaves it up to the implementor to decide what it means to be a "fast" integer type.

An implementation is required to define these for the following N: 8, 16, 32, 64.

INT_FASTN_MIN INT_FASTN_MAX UINT_FASTN_MAX

[edit] Integers wide enough to hold pointers (optional)

intptr_t uintptr_t

INTPTRN_MIN INTPTRN_MAX UINTPTRN_MAX

[edit] Greatest-width integer types

intmax_t uintmax_t

INTMAXN_MIN INTMAXN_MAX UINTMAXN_MAX

INTMAX_C(value) UINTMAX_C(value)

[edit] Other integer limits

PTRDIFF_MIN PTRDIFF_MAX

SIZE_MAX

WCHAR_MIN WCHAR_MAX

WINT_MIN WINT_MAX

SIG_ATOMIC_MIN SIG_ATOMIC_MAX

[edit] Criticisms and caveats

  • Some (non-conforming) implementations tack C99 support on top of a C89 runtime library. One of the consequences of this is that the new printf and scanf specifiers aren't recognized and will probably lead to something undefined. The typical ways of working around this are:
    • The most common (and the most wrong) way is to use the long or unsigned long types as an intermediate step and pass these types into printf or scanf. This works reasonably well for the exact, minimum, and fast integer types less than 32-bits but may cause trouble with ptrdiff_t and size_t and the types larger than 32-bits, typically on platforms that use 32-bit longs and 64-bit pointers.
    • Not using scanf directly but manually reading in a buffer, calling strto[i|u]max, and then converting it to the desired type. This doesn't help with printing out integers though.
    • Downloading a 3rd-party printf and scanf library that is C99 compatible.
    • Using the C99 standard printing format specifiers. PRId64 for example. These are declared in inttypes.h.
  • The rules for integer rank and corresponding integer types may force implementers to choose the lesser of two evils in not supporting an integer type, making a bad compromise, or supporting an integer type a non-conforming way.
    • For example, there are machines that either have special support for an extremely large signed integer register or an extremely large unsigned integer register without supporting the other type. An implementation can either choose not to expose this to a C implementation, synthesize a slow type as the corresponding integer type, synthesizing a weird corresponding integer type, or expose the integer to the programmer without setting it to the [u]intmax_t types or synthesizing a corresponding integer type.
  • The [u]intN_t types are a compromise between the desire to have guaranteed two's complement integer types and the desire to have guaranteed types with no padding bits (as opposed to a more fine grained approach which would define more types). Because of the "all or nothing" approach to the [u]intN_t types, an implementation might have to play the same sort of games described above depending on whether they care about speed, programmer convenience, or standards conformance.

[edit] See also

[edit] Footnotes

  1. ^ technically, it actually allows 0 or more value bits, but the only way you can construct this is with a single-bit bit-field of a signed integer
  2. ^ The standard doesn't require this type to be typedefed to a character type

[edit] Downloads

As stdint.h is not shipped with Visual Studio C++ products and older C++ compilers, you may want to use some external one.

  • pstdint.h - A cross-platform, free implementation from Paul Hsieh. This implementation was tested on the following compilers, all with 0 warnings at their highest respective settings: Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio.net (VC7), Intel C++ 4.0, GNU gcc v3.3.3.
  • stdint.h - This stdint.h may be used with Microsoft compilers only. But it is fully C99 compliant and may be used with similar inttypes.h. This implementation was tested with Microsoft Visual Studio .NET 2003, Microsoft Visual Studio 2005 and Microsoft Visual Studio 2008.