Type
(Siehe auch arithmetic types für Details zu den meisten eingebauten Typen und die Liste der typbezogenen Hilfsmittel die von der C-Bibliothek bereitgestellt werden.)
Objekte , Funktionen und Ausdrücke besitzen eine Eigenschaft namens Typ , die die Interpretation des binären Werts bestimmt, der in einem Objekt gespeichert oder durch einen Ausdruck ausgewertet wird.
Inhaltsverzeichnis |
Typklassifizierung
Das C-Typsystem besteht aus den folgenden Typen:
- der Typ void
- Grundtypen
-
- der Typ char
- vorzeichenbehaftete Ganzzahltypen
-
- Standard: signed char , short , int , long , long long (seit C99)
|
(seit C23) |
|
(seit C99) |
-
- vorzeichenlose Ganzzahltypen
-
- Standard: _Bool , (since C99) unsigned char , unsigned short , unsigned int , unsigned long , unsigned long long (since C99)
|
(seit C23) |
|
(seit C99) |
-
- Gleitkommatypen
-
- Reelle Gleitkommatypen: float , double , long double
|
(seit C23) |
|
(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
const
-,
volatile
- und
restrict
-Qualifizierer (sofern durch die Semantik des Qualifizierers erlaubt).
Typgruppen
- Objekttypen : alle Typen, die keine Funktionstypen sind
- Zeichentypen : char , signed char , unsigned char
- Ganzzahltypen : char , vorzeichenbehaftete Ganzzahltypen, vorzeichenlose Ganzzahltypen, Aufzählungstypen
- reale Typen : Ganzzahltypen und Gleitkommatypen
- arithmetische Typen : Ganzzahltypen und Gleitkommatypen
- skalare Typen : arithmetische Typen, Zeigertypen , und nullptr_t (seit C23)
- zusammengesetzte Typen : Arraytypen und Strukturtypen
- abgeleitete Deklaratortypen : Arraytypen, Funktionstypen und Zeigertypen
Das Konstruieren eines vollständigen Objekttyps, sodass die Anzahl der Bytes in seiner Objektrepräsentation nicht im Typ
size_t
darstellbar ist (d.h. dem Ergebnistyp des
sizeof
Operators)
, einschließlich der Bildung eines solchen VLA-Typs zur Laufzeit,
(seit C99)
ist undefiniertes Verhalten.
Kompatible Typen
In einem C-Programm müssen die Deklarationen, die sich auf dasselbe Objekt oder dieselbe Funktion in verschiedenen Übersetzungseinheiten beziehen, nicht denselben Typ verwenden. Sie müssen nur ausreichend ähnliche Typen verwenden, formal bekannt als kompatible Typen . Dasselbe gilt für Funktionsaufrufe und Lvalue-Zugriffe; Argumenttypen müssen kompatibel mit Parametertypen sein und der Lvalue-Ausdrucktyp muss kompatibel mit dem Objekttyp sein, auf den zugegriffen wird.
Die Typen
T
und
U
sind kompatibel, wenn
-
sie sind vom gleichen Typ (gleicher Name oder durch eine
typedefeingeführte Aliase) - sie sind identisch cvr-qualifizierte Versionen kompatibler unqualifizierter Typen
- sie sind Zeigertypen und zeigen auf kompatible Typen
- sie sind Arraytypen, und
-
- ihre Elementtypen kompatibel sind, und
- wenn beide eine konstante Größe haben, diese Größe gleich ist. Hinweis: Arrays unbekannter Grenze sind mit jedem Array kompatiblen Elementtyps kompatibel. VLA ist mit jedem Array kompatiblen Elementtyps kompatibel. (seit C99)
- sie sind beide Struktur-/Union-/Aufzählungstypen, und
-
- (C99) falls einer mit einem Tag deklariert wird, muss der andere ebenfalls mit demselben Tag deklariert werden.
- wenn beide vollständige Typen sind, müssen ihre Mitglieder genau in der Anzahl übereinstimmen, mit kompatiblen Typen deklariert sein und übereinstimmende Namen haben.
- zusätzlich, wenn es sich um Enumerationen handelt, müssen entsprechende Mitglieder auch dieselben Werte haben.
- zusätzlich, wenn es sich um Strukturen oder Unions handelt,
-
- Entsprechende Mitglieder müssen in derselben Reihenfolge deklariert werden (nur bei Strukturen)
- Entsprechende Bitfelder müssen dieselben Breiten haben.
- einer ist ein Aufzählungstyp und der andere ist der zugrundeliegende Typ dieser Aufzählung
- es sich um Funktionstypen handelt, und
-
- ihre Rückgabetypen sind kompatibel
- beide verwenden Parameterlisten, die Anzahl der Parameter (einschließlich der Verwendung der Ellipse) ist gleich, und die entsprechenden Parameter haben nach Anwendung von Array-zu-Zeiger- und Funktion-zu-Zeiger-Typanpassungen und nach Entfernen von Top-Level-Qualifizierern kompatible Typen
|
(bis C23) |
Der Typ char ist nicht kompatibel mit signed char und nicht kompatibel mit unsigned char .
Wenn zwei Deklarationen auf dasselbe Objekt oder dieselbe Funktion verweisen und keine kompatiblen Typen verwenden, ist das Verhalten des Programms undefiniert.
// Übersetzungseinheit 1 struct S { int a; }; extern struct S *x; // kompatibel mit TU2's x, aber nicht mit TU3's x // Übersetzungseinheit 2 struct S; extern struct S *x; // kompatibel mit beiden x's // Übersetzungseinheit 3 struct S { float a; }; extern struct S *x; // kompatibel mit TU2's x, aber nicht mit TU1's x // das Verhalten ist undefiniert
// Übersetzungseinheit 1 #include <stdio.h> struct s { int i; }; // kompatibel mit TU3's s, aber nicht mit TU2's extern struct s x = {0}; // kompatibel mit TU3's x extern void f(void); // kompatibel mit TU2's f int main() { f(); return x.i; } // Übersetzungseinheit 2 struct s { float f; }; // kompatibel mit TU4's s, aber nicht mit TU1's s extern struct s y = {3.14}; // kompatibel mit TU4's y void f() // kompatibel mit TU1's f { return; } // Übersetzungseinheit 3 struct s { int i; }; // kompatibel mit TU1's s, aber nicht mit TU2's s extern struct s x; // kompatibel mit TU1's x // Übersetzungseinheit 4 struct s { float f; }; // kompatibel mit TU2's s, aber nicht mit TU1's s extern struct s y; // kompatibel mit TU2's y // das Verhalten ist wohldefiniert: nur mehrere Deklarationen // von Objekten und Funktionen müssen kompatible Typen haben, nicht die Typen selbst
Hinweis: C++ hat kein Konzept kompatibler Typen. Ein C-Programm, das zwei Typen deklariert, die kompatibel aber nicht identisch in verschiedenen Übersetzungseinheiten sind, ist kein gültiges C++-Programm.
Zusammengesetzte Typen
Ein zusammengesetzter Typ kann aus zwei kompatiblen Typen konstruiert werden; es handelt sich um einen Typ, der mit beiden der beiden Typen kompatibel ist und die folgenden Bedingungen erfüllt:
- Wenn beide Typen Array-Typen sind, werden die folgenden Regeln angewendet:
-
- Wenn ein Typ ein Array bekannter konstanter Größe ist, ist der zusammengesetzte Typ ein Array dieser 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.
|
(bis C23) |
- Wenn beide Typen Funktionstypen mit Parametertyplisten sind, ist der Typ jedes Parameters in der zusammengesetzten Parametertypliste der zusammengesetzte Typ der entsprechenden Parameter.
Diese Regeln gelten rekursiv für die Typen, von denen die beiden Typen abgeleitet sind.
// Bei den folgenden zwei Deklarationen im Dateibereich: int f(int (*)(), double (*)[3]); int f(int (*)(char *), double (*)[]); // C23: Fehler: widersprüchliche Typen für 'f' // Der resultierende zusammengesetzte Typ für die Funktion ist: int f(int (*)(char *), double (*)[3]);
Für einen Bezeichner mit interner oder externer Verknüpfung , der in einem Gültigkeitsbereich deklariert wird, in dem eine vorherige Deklaration dieses Bezeichners sichtbar ist, wenn die vorherige Deklaration interne oder externe Verknüpfung spezifiziert, wird der Typ des Bezeichners bei der späteren Deklaration zum zusammengesetzten Typ.
Unvollständige Typen
Ein unvollständiger Typ ist ein Objekttyp, dem ausreichende Informationen fehlen, um die Größe der Objekte dieses Typs zu bestimmen. Ein unvollständiger Typ kann an einem bestimmten Punkt in der Übersetzungseinheit vervollständigt werden.
Die folgenden Typen sind unvollständig:
- der Typ void . Dieser Typ kann nicht vervollständigt werden.
- Array-Typ unbekannter Größe. Er kann durch eine spätere Deklaration vervollständigt werden, die die Größe angibt.
extern char a[]; // der Typ von a ist unvollständig (dies erscheint typischerweise in einem Header) char a[10]; // der Typ von a ist nun vollständig (dies erscheint typischerweise in einer Quelldatei)
- Struktur- oder Union-Typ unbekannten Inhalts. Er kann durch eine Deklaration derselben Struktur oder Union vervollständigt werden, die seinen Inhalt später im selben Gültigkeitsbereich definiert.
struct node { struct node* next; // struct node ist an diesem Punkt unvollständig }; // struct node ist an diesem Punkt vollständig
Typnamen
Ein Typ muss möglicherweise in einem anderen Kontext als der Deklaration benannt werden. In diesen Situationen wird ein Typname verwendet, der grammatikalisch genau dasselbe ist wie eine Liste von type-specifiers und type-qualifiers , gefolgt vom declarator (siehe declarations ), wie er verwendet würde, um ein einzelnes Objekt oder eine Funktion dieses Typs zu deklarieren, mit der Ausnahme, dass der Bezeichner weggelassen wird:
int n; // Deklaration eines int sizeof(int); // Verwendung eines Typnamens int *a[3]; // Deklaration eines Arrays von 3 Zeigern auf int sizeof(int *[3]); // Verwendung eines Typnamens int (*p)[3]; // Deklaration eines Zeigers auf ein Array von 3 int sizeof(int (*)[3]); // Verwendung eines Typnamens int (*a)[*] // Deklaration eines Zeigers auf VLA (in einem Funktionsparameter) sizeof(int (*)[*]) // Verwendung eines Typnamens (in einem Funktionsparameter) int *f(void); // Deklaration einer Funktion sizeof(int *(void)); // Verwendung eines Typnamens int (*p)(void); // Deklaration eines Zeigers auf eine Funktion sizeof(int (*)(void)); // Verwendung eines Typnamens int (*const a[])(unsigned int, ...) = {0}; // Array von Zeigern auf Funktionen sizeof(int (*const [])(unsigned int, ...)); // Verwendung eines Typnamens
Außer die redundanten Klammern um den Bezeichner sind in einem Typnamen bedeutungsvoll und repräsentieren "Funktion ohne Parameterangabe":
int (n); // deklariert n vom Typ int sizeof(int ()); // verwendet Typ "Funktion, die int zurückgibt"
Typnamen 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; // Der Typname "struct X {int i;}*" im Cast-Ausdruck // führt den neuen Typ "struct X" ein struct X x = {1}; // struct X ist jetzt im Gültigkeitsbereich
Referenzen
- C23-Standard (ISO/IEC 9899:2024):
-
- 6.2.5 Typen (S.: TBD)
-
- 6.2.6 Darstellungen 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 Darstellungen 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 Darstellungen 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 Darstellungen 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 Kompatible Typen und zusammengesetzte Typen
Siehe auch
|
C++ Dokumentation
für
Type
|