stdint.h, inttypes.h, limits.h

Ein Integer ist in den Sprachen C und C++ definiert als eine zusammengehörige Menge an Bits, welche eine Ganzzahl codieren. Je nach Anwendung ist die Ganzzahl zudem als vorzeichenbehaftet oder vorzeichenlos zu interpretieren. Die Anzahl an Bits, welche für die Codierung benötigt wird, definiert den Werteumfang des Typs.

Mit dem Standard C99 wurden die Bibliotheken stdint und inttypes eingeführt, welche eine präzise Festlegung der benötigten Bits erlauben.

Integer-Typen mit Bit-Angabe

C
C++
#include <stdint.h>
#include <cstdint>

In der stdint-Bibliothek werden Integer-Typen bereitgestellt, welche eine unterschiedliche Anzahl Bits aufweisen und entweder vorzeichenbehaftet oder vorzeichenlos sind. Je nach Anwendungsgebiet ist erwünscht, dass die gewünschte Anzahl Bits exakt eingehalten wird, es nur eine Mindestanforderung ist, oder dass es demjenigen Typ entspricht, welcher am schnellsten vom Prozessor verarbeitet werden kann.

intN_t          signed-Integer with exactly N bits.
uintN_t         unsigned-Integer with exactly N bits.
int_leastN_t    signed-Integer with at least N bits.
uint_leastN_t   unsigned-Integer with at least N bits.
int_fastN_t     signed-Integer with at least N bits and fastest processing.
uint_fastN_t    unsigned-Integer with at least N bits and fastest processing.

Das N steht für die gewünschte Anzahl Bits. Jeder Compiler gemäss C99-Standard muss mindestens die Integer-Typen mit 8, 16, 32 und 64 Bits bereitstellen. Es steht einem Compiler jedoch frei, auch weitere Typen bereitzustellen, beispielsweise mit 24 Bits.

Ein 32-Bit Integer kann beispielsweise folgendermassen auf verschiedene Arten deklariert werden:

#include <stdint.h>

int main (void)
{
  int32_t        myint1;
  uint32_t       myint2;
  int_least32_t  myint3;
  uint_least32_t myint4;
  int_fast32_t   myint5;
  uint_fast32_t  myint6;
  return 0;
}

Vorsicht: Obige Angaben müssen auf gewissen Systemen mit Vorsicht genossen werden. Die Typen mit exakter Anzahl Bits beispielsweise existieren nur dann, wenn das System eine entsprechende Speicherung ohne Padding-Bits überhaupt beherrscht und zudem die signed-Variante mit dem Zweierkomplement codiert wird. Es ist somit auch nur bei den exakten Typen garantiert, dass die vorzeichenbehafteten Zahlen im Zweierkomplement codiert werden. Bei modernen Systemen kann jedoch grundsätzlich davon ausgegangen werden, dass dem so ist.

Der Autor empfielt grundsätzlich, diese Typen anstelle der traditionellen Typ-Modifikatoren (siehe unten) zu nutzen. Auf modernen Systemen und mit modernen Compilern sind obengenannte Typen allesamt definiert und führen zu plattformunabhängigem Code.

In der stdint-Bibliothek werden noch weitere Typen definiert. Diese sind jedoch (vorerst) auf dieser Seite nicht aufgeführt.

Minimal- und Maximalwerte (Limits)

Zu all den Typen, welche gemäss obiger Liste definiert sind, werden gleichzeitig verschiedene Makros angeboten, um die vorliegenden Minimal- und Maximalwerte abzufragen:

INTN_MIN            Minimum value of type intN_t
INTN_MAX            Maximum value of type intN_t
UINTN_MAX           Maximum value of type uintN_t
INT_LEASTN_MIN      Minimum value of type int_leastN_t
INT_LEASTN_MAX      Maximum value of type int_leastN_t
UINT_LEASTN_MAX     Maximum value of type uint_leastN_t
INT_FASTN_MIN       Minimum value of type int_fastN_t
INT_FASTN_MAX       Maximum value of type int_fastN_t
UINT_FASTN_MAX      Maximum value of type uint_fastN_t

Wiederum steht N für die Anzahl Bits des entsprechenden Typs. Das Makro für den Minimalwert eines unsigned-Typs fehlt, da dieser stets als 0 (Null) definiert ist.

Im Folgenden werden illustrativ die Werte der exakten Typen aufgelistet. Diese Werte sollten für die meisten Nutzer von Nutzen sein:





-128
 127
 255
-32768
 32767
 65535
-2147483648
 2147483647
 4294967295
-9223372036854775808
 9223372036854775807
 18446744073709551615
#include <stdio.h>
#include <stdint.h>

int main(){
  printf("%i\n",    INT8_MIN);
  printf(" %i\n",   INT8_MAX);
  printf(" %u\n",   UINT8_MAX);
  printf("%i\n",    INT16_MIN);
  printf(" %i\n",   INT16_MAX);
  printf(" %u\n",   UINT16_MAX);
  printf("%i\n",    INT32_MIN);
  printf(" %i\n",   INT32_MAX);
  printf(" %u\n",   UINT32_MAX);
  printf("%lli\n",  INT64_MIN);
  printf(" %lli\n", INT64_MAX);
  printf(" %llu\n", UINT64_MAX);
  return 0;
}

Diese Minimal- und Maximal-Werte werden auch als Limits (Grenzwerte) bezeichnet, da sie auf traditionellem Wege durch die limits-Bibliothek abgefragt werden konnten. Siehe dazu den Abschnitt weiter unten.

Die stdint-Bibliothek definiert noch einige weitere Makros, welche jedoch (vorerst) hier auf dieser Seite nicht aufgeführt werden.

Makros für printf und scanf

Bei der Ein- und Ausgabe mittels printf und scanf muss mittels Formatierungs-Zeichen (beispielsweise "%hhd") angegeben werden, wie ein übergebenes Argument interpretiert werden soll. Bei der Einführung der neuen Integer-Typen in der stdint-Bibliothek wurde für jeden neuen Typ auch ein entsprechendes Makro definiert, welches die entsprechenden Formatierungs-Zeichen festlegt. All diese Makros stehen zur Verfügung, wenn folgende Bibliothek eingebunden wird:

C
C++
#include <inttypes.h>
#include <cinttypes>

Die Makros für printf beginnen mit PRI und die Makros für scanf beginnen mit SCN. Die weiteren Angaben beziehen sich auf das Ein- und Ausgabeformat sowie den Typ des Argumentes.

PRIiN   PRIiLEASTN   PRIiFASTN   integer
PRIdN   PRIdLEASTN   PRIdFASTN   signed decimal number
PRIuN   PRIuLEASTN   PRIuFASTN   unsigned decimal number
PRIoN   PRIoLEASTN   PRIoFASTN   octal number
PRIxN   PRIxLEASTN   PRIxFASTN   Lower case hexadecimal number
PRIXN   PRIXLEASTN   PRIXFASTN   Upper case hexadecimal number

SCNiN   SCNiLEASTN   SCNiFASTN   integer
SCNdN   SCNdLEASTN   SCNdFASTN   signed decimal number
SCNuN   SCNuLEASTN   SCNuFASTN   unsigned decimal number
SCNoN   SCNoLEASTN   SCNoFASTN   octal number
SCNxN   SCNxLEASTN   SCNxFASTN   Lower case hexadecimal number
SCNXN   SCNXLEASTN   SCNXFASTN   Upper case hexadecimal number

Die Unterscheidung zwischen d und i macht nur bei scanf Sinn. Bei printf bewirken beide Angaben dasselbe.

Diese Makros werden verwendet, indem sie durch Hintereinanderhängen des Formatstrings an die gewünschten Positionen geschrieben werden:






123
50000
75bcd15
34327724461477777
int8_t         myint1 = 123;
uint_least16_t myint2 = 50000;
int32_t        myint3 = 123456789;
int_fast64_t   myint4 = 999999999999999;

printf("%" PRId8       "\n", myint1);
printf("%" PRIuLEAST16 "\n", myint2);
printf("%" PRIx32      "\n", myint3);
printf("%" PRIoFAST64  "\n", myint4);

Es ist zu beachten, dass die Makros OHNE das Prozentzeichen % definiert sind. Dadurch ist es möglich, weitere Formatierungs-Zeichen hinzuschreiben:

123
   123
000123
printf("%"   PRIi32 "\n", 123);
printf("%6"  PRIi32 "\n", 123);
printf("%06" PRIi32 "\n", 123);

Die inttypes-Bibliothek definiert noch einige weitere Makros, welche jedoch (vorerst) hier auf dieser Seite nicht aufgeführt werden.

Der traditionelle Weg: Die limits-Bibliothek

Die in die Sprachen C und C++ eingebauten Basistypen char, short, int, long und long long weisen je nach System eine unterschiedliche Anzahl Bits auf und können dementsprechend einen mehr oder weniger grossen Zahlenbereich abdecken. Die im aktuell verwendeten Compiler verfügbaren Minimal- und Maximalwerte der Basistypen sind als Konstanten in der limits-Bibliothek definiert.

C
C++
#include <limits.h>
#include <climits>

Der Autor empfielt, wenn immer möglich die limits-Bibliothek nicht mehr zu verwenden und stattdessen mit der stdint-Bibliothek zu arbeiten. Siehe oben.

Folgendes Beispielprogramm soll zur Auflistung der Makros genügen:





-128
 127
 255
-32768
 32767
 65535
-2147483648
 2147483647
 4294967295
-2147483648
 2147483647
 4294967295
-9223372036854775808
 9223372036854775807
 18446744073709551615
#include <stdio.h>
#include <limits.h>

int main(){
  printf("%hhi\n",  SCHAR_MIN);
  printf(" %hhi\n", SCHAR_MAX);
  printf(" %hhu\n", UCHAR_MAX);
  printf("%hi\n",   SHRT_MIN);
  printf(" %hi\n",  SHRT_MAX);
  printf(" %hu\n",  USHRT_MAX);
  printf("%i\n",    INT_MIN);
  printf(" %i\n",   INT_MAX);
  printf(" %u\n",   UINT_MAX);
  printf("%i\n",    LONG_MIN);
  printf(" %i\n",   LONG_MAX);
  printf(" %u\n",   ULONG_MAX);
  printf("%lli\n",  LLONG_MIN);
  printf(" %lli\n", LLONG_MAX);
  printf(" %llu\n", ULLONG_MAX);
  return 0;
}

Es ist zu beachten, dass je nach System die ausgegebenen Werte durchaus unterschiedlich sein mögen, oder aber gewisse Makros gar nicht definiert sind. Die auf dieser Seite angegebenen Werte sind diejenigen, welche auf dem System des Autors ausgegeben wurden.

Es ist des weiteren zu beachten, dass keine Makros für den Minimalwert eines unsigned-Typs existieren. Dieser ist in jedem Fall 0 (Null).

In der limits-Bibliothek befinden sich zudem noch ein paar weitere Makros, welche jedoch für die alltägliche Programmierung kaum relevant sind. Sie sind in der folgenden Tabelle zusammen mit den beim Autor definierten Werten aufgelistet, allerdings wird auf dieser Seite nicht weiter darauf eingegangen. Der Interessierte Leser möge die Bedeutungen in der limits-Bibliothek oder in anderen Quellen nachlesen.

CHAR_BIT        8    Number of bits in a char
MB_LEN_MAX      6    Maximum number of bytes of a multi-byte character
CHAR_MIN     -128    Minimum value of char without signed or unsigned modifier
CHAR_MAX      127    Maximum value of char without signed or unsigned modifier

Des weiteren definieren gewisse Implementationen noch zusätzliche Makros, welche jedoch weniger neue Funktionalität einführen, denn einfach die bestehende mit neuen Symbolen zu belegen.

LONG_LONG_MIN     The same as LLONG_MIN
LONG_LONG_MAX     The same as LLONG_MAX
ULONG_LONG_MAX    The same as ULLONG_MAX