Namensräume
Varianten
Aktionen

Typ

Von cppreference.com
< c‎ | Sprache

(Siehe auch arithmetische Typen für Details zu den meisten integrierten Typen und die Liste der typbezogenen Hilfsmittel, die von der C-Bibliothek bereitgestellt werden.)

Objekte, Funktionen und Ausdrücke haben eine Eigenschaft namens Typ, die die Interpretation des binären Werts bestimmt, der in einem Objekt gespeichert oder von dem Ausdruck ausgewertet wird.

Inhalt

[bearbeiten] Typklassifizierung

Das C-Typsystem besteht aus den folgenden Typen:

  • der Typ void
  • Basistypen
  • der Typ char
  • vorzeichenbehaftete Ganzzahltypen
  • Standard: signed char, short, int, long, long long(seit C99)
  • Bit-präzise: _BitInt(N) wobei N ein ganzzahliger konstanter Ausdruck ist, der die Anzahl der Bits angibt, die zur Darstellung des Typs verwendet werden, einschließlich des Vorzeichenbits. Jeder Wert von N bezeichnet einen unterschiedlichen Typ.
(seit C23)
  • Erweitert: Implementierungsdefiniert, z.B. __int128
(seit C99)
  • vorzeichenlose Ganzzahltypen
  • Standard: _Bool,(seit C99) unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long(seit C99)
  • Bit-präzise: unsigned _BitInt(N) wobei N ein ganzzahliger konstanter Ausdruck ist, der die Anzahl der Bits angibt, die zur Darstellung des Typs verwendet werden. Jeder Wert von N bezeichnet einen unterschiedlichen Typ. Diese Kategorie enthält den Typ unsigned _BitInt(1), der keinen entsprechenden bit-präzisen vorzeichenbehafteten Ganzzahltyp hat.
(seit C23)
  • Erweitert: Implementierungsdefiniert, z.B. __uint128
(seit C99)
  • Gleitkommatypen
  • reelle Gleitkommatypen: float, double, long double
  • dezimale reelle Gleitkommatypen: _Decimal32, _Decimal64, _Decimal128
(seit C23)
  • komplexe Typen: float _Complex, double _Complex, long double _Complex
  • imaginäre Typen: float _Imaginary, double _Imaginary, long double _Imaginary
(seit C99)
  • abgeleitete Typen
(seit C11)

Für jeden oben aufgeführten Typ können mehrere qualifizierte Versionen seines Typs existieren, entsprechend den Kombinationen von einem, zwei oder allen drei der Qualifizierer const, volatile und restrict (sofern von der Semantik des Qualifizierers erlaubt).

[bearbeiten] Typengruppen

  • Objekttypen: alle Typen, die keine Funktionstypen sind
  • Zeichen-Typen: char, signed char, unsigned char
  • Ganzzahltypen: char, vorzeichenbehaftete Ganzzahltypen, vorzeichenlose Ganzzahltypen, Aufzählungstypen
  • reelle Typen: Ganzzahltypen und reelle Gleitkommatypen
  • Arithmetische Typen: Ganzzahltypen und Gleitkommatypen
  • Skalartypen: arithmetische Typen, Zeigertypen, und nullptr_t(seit C23)
  • Aggregattypen: Arraytypen und Strukturtypen
  • Abgeleitete Deklarator-Typen: Arraytypen, Funktionstypen und Zeigertypen

Die Konstruktion eines vollständigen Objekttyps, bei dem die Anzahl der Bytes in seiner Objekt-Repräsentation nicht im Typ size_t darstellbar ist (d.h. dem Ergebnistyp des sizeof-Operators), einschließlich der Laufzeitbildung eines solchen VLA-Typs,(seit C99) ist undefiniertes Verhalten.

[bearbeiten] Kompatible Typen

In einem C-Programm müssen Deklarationen, die sich auf dasselbe Objekt oder dieselbe Funktion in unterschiedlichen Übersetzungseinheiten beziehen, nicht denselben Typ verwenden. Sie müssen nur ausreichend ähnliche Typen verwenden, die formal als kompatible Typen bekannt sind. Dasselbe gilt für Funktionsaufrufe und lvalue-Zugriffe; Argumenttypen müssen kompatibel mit Parametertypen sein und der Typ eines lvalue-Ausdrucks muss kompatibel mit dem Objekttyp sein, auf den zugegriffen wird.

Die Typen T und U sind kompatibel, wenn:

  • sie derselbe Typ sind (derselbe Name oder Aliasse, die durch ein typedef eingeführt wurden)
  • sie identisch cvr-qualifizierte Versionen von kompatiblen unqualifizierten Typen sind
  • sie Zeigertypen sind und auf kompatible Typen zeigen
  • sie Arraytypen sind und
  • ihre Elementtypen kompatibel sind, und
  • falls beide eine konstante Größe haben, diese Größe gleich ist. Hinweis: Arrays unbekannter Größe sind mit jedem Array eines kompatiblen Elementtyps kompatibel. VLA ist mit jedem Array eines kompatiblen Elementtyps kompatibel.(seit C99)
  • beide Struktur-/Union-/Aufzählungstypen sind, und
  • (C99)Wenn einer mit einem Tag deklariert ist, muss der andere ebenfalls mit demselben Tag deklariert sein.
  • wenn beide vollständige Typen sind, müssen ihre Mitglieder in Anzahl genau übereinstimmen, mit kompatiblen Typen deklariert sein und übereinstimmende Namen haben.
  • Zusätzlich, wenn es sich um Aufzählungen handelt, müssen entsprechende Mitglieder auch dieselben Werte haben.
  • Zusätzlich, wenn es sich um Strukturen oder Unions handelt,
  • Entsprechende Mitglieder müssen in der gleichen Reihenfolge deklariert sein (nur Strukturen).
  • Entsprechende Bitfelder müssen dieselbe Breite haben.
  • einer ein Aufzählungstyp ist und der andere der zugrundeliegende Typ dieser Aufzählung ist
  • sie Funktionstypen sind und
  • ihre Rückgabetypen kompatibel sind
  • sie beide Parameterlisten verwenden, die Anzahl der Parameter (einschließlich der Verwendung von Auslassungspunkten) gleich ist und die entsprechenden Parameter, nachdem Array-zu-Zeiger- und Funktions-zu-Zeiger-Typanpassungen angewendet wurden und nach Entfernung von Top-Level-Qualifizierern, kompatible Typen haben
  • einer eine Definition im alten Stil (parameterlos) ist, der andere eine Parameterliste hat, die Parameterliste keine Auslassungspunkte verwendet und jeder Parameter (nach Funktionsparametertypanpassung) mit dem entsprechenden Parameter im alten Stil nach Standardargumentpromotionen kompatibel ist
  • einer eine Deklaration im alten Stil (parameterlos) ist, der andere eine Parameterliste hat, die Parameterliste keine Auslassungspunkte verwendet und alle Parameter (nach Funktionsparametertypanpassung) von Standardargumentpromotionen unberührt bleiben
(bis C23)

Der Typ char ist nicht kompatibel mit signed char und nicht kompatibel mit unsigned char.

Wenn zwei Deklarationen dasselbe Objekt oder dieselbe Funktion bezeichnen und keine kompatiblen Typen verwenden, ist das Verhalten des Programms undefiniert.

// Translation Unit 1
struct S { int a; };
extern struct S *x; // compatible with TU2's x, but not with TU3's x
 
// Translation Unit 2
struct S;
extern struct S *x; // compatible with both x's
 
// Translation Unit 3
struct S { float a; };
extern struct S *x; // compatible with TU2's x, but not with TU1's x
 
// the behavior is undefined
// Translation Unit 1
#include <stdio.h>
 
struct s { int i; }; // compatible with TU3's s, but not TU2's
extern struct s x = {0}; // compatible with TU3's x
extern void f(void); // compatible with TU2's f
 
int main()
{
    f();
    return x.i;
}
 
// Translation Unit 2
struct s { float f; }; // compatible with TU4's s, but not TU1's s
extern struct s y = {3.14}; // compatible with TU4's y
void f() // compatible with TU1's f
{
    return;
}
 
// Translation Unit 3
struct s { int i; }; // compatible with TU1's s, but not TU2's s
extern struct s x; // compatible with TU1's x
 
// Translation Unit 4
struct s { float f; }; // compatible with TU2's s, but not TU1's s
extern struct s y; // compatible with TU2's y
 
// the behavior is well-defined: only multiple declarations
// of objects and functions must have compatible types, not the types themselves

Hinweis: C++ hat kein Konzept von kompatiblen Typen. Ein C-Programm, das zwei Typen in verschiedenen Übersetzungseinheiten deklariert, die kompatibel, aber nicht identisch sind, ist kein gültiges C++-Programm.

[bearbeiten] Zusammengesetzte Typen

Ein zusammengesetzter Typ kann aus zwei Typen gebildet werden, die kompatibel sind; er ist ein Typ, der mit beiden der beiden Typen kompatibel ist und die folgenden Bedingungen erfüllt:

  • Wenn beide Typen Arraytypen sind, werden die folgenden Regeln angewendet:
  • Wenn ein Typ ein Array mit bekannter konstanter Größe ist, ist der zusammengesetzte Typ ein Array dieser Größe.
  • Andernfalls, wenn ein Typ ein VLA ist, dessen Größe durch einen nicht ausgewerteten Ausdruck angegeben wird, ist ein Programm, das den zusammengesetzten Typ beider Typen benötigt, undefiniertes Verhalten.
  • Andernfalls, wenn ein Typ ein VLA ist, dessen Größe angegeben ist, ist der zusammengesetzte Typ ein VLA dieser Größe.
  • Andernfalls, wenn ein Typ ein VLA unbekannter Größe ist, ist der zusammengesetzte Typ ein VLA unbekannter Größe.
(seit C99)
  • Andernfalls sind beide Typen Arrays unbekannter Größe und der zusammengesetzte Typ ist ein Array unbekannter Größe.
Der Elementtyp des zusammengesetzten Typs ist der zusammengesetzte Typ der beiden Elementtypen.
  • Wenn nur ein Typ ein Funktionstyp mit einer Parameter-Typ-Liste (ein Funktionsprototyp) ist, ist der zusammengesetzte Typ ein Funktionsprototyp mit der Parameter-Typ-Liste.
(bis C23)
  • Wenn beide Typen Funktionstypen mit Parameter-Typ-Listen sind, ist der Typ jedes Parameters in der zusammengesetzten Parameter-Typ-Liste der zusammengesetzte Typ der entsprechenden Parameter.

Diese Regeln gelten rekursiv für die Typen, von denen die beiden Typen abgeleitet sind.

// Given the following two file scope declarations:
int f(int (*)(), double (*)[3]);
int f(int (*)(char *), double (*)[]); // C23: Error: conflicting types for 'f'
// The resulting composite type for the function is:
int f(int (*)(char *), double (*)[3]);

Für einen Bezeichner mit interner oder externer Bindung, der in einem Geltungsbereich deklariert wird, in dem eine vorherige Deklaration dieses Bezeichners sichtbar ist, wird, wenn die vorherige Deklaration eine interne oder externe Bindung angibt, der Typ des Bezeichners bei der späteren Deklaration zum zusammengesetzten Typ.

[bearbeiten] Unvollständige Typen

Ein unvollständiger Typ ist ein Objekttyp, dem ausreichende Informationen fehlen, um die Größe von Objekten dieses Typs zu bestimmen. Ein unvollständiger Typ kann zu einem bestimmten Zeitpunkt in der Übersetzungseinheit vervollständigt werden.

Die folgenden Typen sind unvollständig:

  • der Typ void. Dieser Typ kann nicht vervollständigt werden.
  • Arraytyp unbekannter Größe. Er kann durch eine spätere Deklaration, die die Größe angibt, vervollständigt werden.
extern char a[]; // the type of a is incomplete (this typically appears in a header)
char a[10];      // the type of a is now complete (this typically appears in a source file)
  • Struktur- oder Union-Typ unbekannten Inhalts. Er kann durch eine Deklaration derselben Struktur oder Union, die seinen Inhalt später im selben Geltungsbereich definiert, vervollständigt werden.
struct node
{
    struct node* next; // struct node is incomplete at this point
}; // struct node is complete at this point

[bearbeiten] Typennamen

Ein Typ muss möglicherweise in anderen Kontexten als der Deklaration benannt werden. In diesen Situationen wird ein Typname verwendet, der grammatisch exakt gleich ist wie eine Liste von Typ-Spezifizierern und Typ-Qualifizierern, gefolgt von dem Deklarator (siehe Deklarationen), wie er zur Deklaration eines einzelnen Objekts oder einer Funktion dieses Typs verwendet würde, nur dass der Bezeichner weggelassen wird.

int n; // declaration of an int
sizeof(int); // use of type name
 
int *a[3]; // declaration of an array of 3 pointers to int
sizeof(int *[3]); // use of type name
 
int (*p)[3]; // declaration of a pointer to array of 3 int
sizeof(int (*)[3]); // use of type name
 
int (*a)[*] // declaration of pointer to VLA (in a function parameter)
sizeof(int (*)[*]) // use of type name (in a function parameter)
 
int *f(void); // declaration of function
sizeof(int *(void)); // use of type name
 
int (*p)(void); // declaration of pointer to function
sizeof(int (*)(void)); // use of type name
 
int (*const a[])(unsigned int, ...) = {0}; // array of pointers to functions
sizeof(int (*const [])(unsigned int, ...)); // use of type name

Abgesehen davon sind überflüssige Klammern um den Bezeichner in einem Typnamen bedeutungsvoll und stellen "Funktion ohne Parameterangabe" dar.

int (n); // declares n of type int
sizeof(int ()); // uses type "function returning int"

Typennamen werden in den folgenden Situationen verwendet:

(seit C99)
(seit C11)


Ein Typname kann einen neuen Typ einführen.

void* p = (void*)(struct X { int i; } *)0;
// type name "struct X {int i;}*" used in the cast expression
// introduces the new type "struct X"
struct X x = {1}; // struct X is now in scope

[bearbeiten] Referenzen

  • C23-Standard (ISO/IEC 9899:2024)
  • 6.2.5 Typen (S. TBD)
  • 6.2.6 Repräsentationen von Typen (S. TBD)
  • 6.2.7 Kompatibler Typ und zusammengesetzter Typ (S. TBD)
  • C17-Standard (ISO/IEC 9899:2018)
  • 6.2.5 Typen (S. 31-33)
  • 6.2.6 Repräsentationen von Typen (S. 31-35)
  • 6.2.7 Kompatibler Typ und zusammengesetzter Typ (S. 35-36)
  • C11-Standard (ISO/IEC 9899:2011)
  • 6.2.5 Typen (S. 39-43)
  • 6.2.6 Repräsentationen von Typen (S. 44-46)
  • 6.2.7 Kompatibler Typ und zusammengesetzter Typ (S. 47-48)
  • C99-Standard (ISO/IEC 9899:1999)
  • 6.2.5 Typen (S. 33-37)
  • 6.2.6 Repräsentationen von Typen (S. 37-40)
  • 6.2.7 Kompatibler Typ und zusammengesetzter Typ (S. 40-41)
  • C89/C90-Standard (ISO/IEC 9899:1990)
  • 3.1.2.5 Typen
  • 3.1.2.6 Kompatibler Typ und zusammengesetzter Typ

[bearbeiten] Siehe auch