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:
- sign and magnitude
- one's complement
- two's complement (the most widely used)
[edit] New integer types
- The types
<something>_t
andu<something>_t
are required to be corresponding integer types.
- For the types that are marked optional, an implementation must either define both
<something>_t
andu<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.
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
orunsigned 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 withptrdiff_t
andsize_t
and the types larger than 32-bits, typically on platforms that use 32-bitlong
s and 64-bit pointers. - Not using
scanf
directly but manually reading in a buffer, callingstrto[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
andscanf
library that is C99 compatible. - Using the C99 standard printing format specifiers. PRId64 for example. These are declared in inttypes.h.
- The most common (and the most wrong) way is to use the
- 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.
- 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
- 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
- ^ 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
- ^ The standard doesn't require this type to be
typedef
ed 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.