C syntax
Das Syntax der C -Programmiersprache ist der Satz von Regeln für das Schreiben von Software in der C Sprache. Es ist so konzipiert, dass Programme, die extrem knapp sind Objektcodeund doch relativ hohe Ebene liefern Datenabstraktion. C war die erste weit verbreitete hochrangige Sprache für tragbare Sprache Betriebssystem Entwicklung.
C Syntax verwendet die Maximales Munch Prinzip.
Datenstrukturen
Primitive Datentypen
Das C Sprache Repräsentiert Zahlen in drei Formen: Integral-, real und Komplex. Diese Unterscheidung spiegelt ähnliche Unterschiede in der wider Befehlssatz Architektur der meisten Zentrale Verarbeitungseinheiten. Integral Datentypen speichern Zahlen im Satz von Ganzzahlen, während real und Komplex Zahlen repräsentieren Zahlen (oder Zahlenpaar) im Satz von reale Nummern in schwimmender Punkt bilden.
Alle C -Ganzzahl -Typen haben signed
und unsigned
Varianten. Wenn signed
oder unsigned
wird in den meisten Umständen nicht explizit spezifiziert signed
wird angenommen. Aus historischen Gründen ist jedoch einfach char
unterscheidet sich von beiden signed char
und unsigned char
. Es kann sich abhängig vom Compiler und dem Zeichensatz um einen signierten Typ oder ein nicht signierter Typ handeln (C garantiert, dass die Mitglieder des C -Basis -Zeichenssatzes positive Werte haben). Ebenfalls, Bitfeld Typen als einfach angegeben int
Kann je nach Compiler unterschrieben oder nicht signiert werden.
Ganzzahltypen
Die Ganzzahltypen von C sind in verschiedenen festen Größen erhältlich, die verschiedene Zahlenbereiche darstellen können. Der Typ char
nimmt genau einen ein Byte (Die kleinste adressierbare Speichereinheit), die normalerweise 8 Bit breit ist. (Obwohl char
Kann eines der "grundlegenden" Charaktere von C darstellen, kann ein breiterer Typ für internationale Zeichensätze erforderlich sein.) Die meisten ganzzahligen Typen haben beide signiert und nicht signiert Sorten, bezeichnet von der signed
und unsigned
Schlüsselwörter. Signierte Ganzzahltypen können a verwenden Zwei ergänzt, Einen Ergänzung, oder Zeichen und Magnitude Darstellung. In vielen Fällen gibt es mehrere äquivalente Möglichkeiten, den Typ zu bestimmen. zum Beispiel, signed short int
und short
sind synonym.
Die Darstellung einiger Typen kann nicht verwendete "Polster" -Bits umfassen, die die Lagerung belegen, aber nicht in der Breite enthalten sind. Die folgende Tabelle enthält eine vollständige Liste der Standard -Ganzzahl -Typen und deren Minimum erlaubte Breite (einschließlich eines Zeichenbits).
Kürzeste Form des Spezifizierers | Mindestbreite (Bits) |
---|---|
_Bool | 1 |
char | 8 |
signed char | 8 |
unsigned char | 8 |
short | 16 |
unsigned short | 16 |
int | 16 |
unsigned int | 16 |
long | 32 |
unsigned long | 32 |
long long [1] | 64 |
unsigned long long [1] | 64 |
Das char
Typ unterscheidet sich von beiden signed char
und unsigned char
, ist jedoch garantiert die gleiche Darstellung wie eine von ihnen. Das _Bool
und long long
Die Typen sind seit 1999 standardisiert und dürfen nicht von älteren C -Compilern unterstützt werden. Typ _Bool
wird normalerweise über die zugegriffen Typedef
Name bool
definiert durch den Standardheader stdbool.h.
Im Allgemeinen werden das für eine bestimmte Plattform implementierte Breiten- und Repräsentationsschema anhand der Maschinenarchitektur ausgewählt, wobei die für andere Plattformen entwickelte einfache Import -Quellcode berücksichtigt wird. Die Breite der int
Der Typ variiert insbesondere bei C -Implementierungen. Es entspricht oft der "natürlichsten" Wortgröße für die spezifische Plattform. Der Standard -Header Limits.h Definiert Makros für die minimalen und maximal repräsentierbaren Werte der auf einer bestimmten Plattform implementierten Standard -Ganzzahl -Typen.
Zusätzlich zu den Standard -Ganzzahl -Typen kann es andere "erweiterte" Ganzzahltypen geben, die für verwendet werden können typedef
s in Standard -Header. Für eine genauere Spezifikation der Breite können und sollten Programmierer verwenden und sollten verwenden typedef
s aus dem Standard -Header stdint.h.
Ganzzahlkonstanten können auf verschiedene Weise in Quellcode angegeben werden. Numerische Werte können als angegeben werden Dezimal (Beispiel: 1022
), Oktal mit null (0) als Präfix (01776
), oder hexadezimal mit 0x (null x) als Präfix (0x3FE
). Ein Zeichen in einzelnen Zitaten (Beispiel: 'R'
), als "Zeichenkonstante" bezeichnet, repräsentiert den Wert dieses Zeichens im Ausführungszeichen mit Typ, mit Typ int
. Mit Ausnahme von Zeichenkonstanten wird der Typ einer Ganzzahlkonstante durch die Breite bestimmt, die erforderlich ist, um den angegebenen Wert darzustellen, ist jedoch immer mindestens so breit wie int
. Dies kann überschrieben werden, indem eine explizite Länge und/oder einen Signierlichkeitsmodifikator angehängt wird. zum Beispiel, 12lu
hat Typ unsigned long
. Es gibt keine negativen Ganzzahlkonstanten, aber der gleiche Effekt kann häufig unter Verwendung eines unären Negationsoperators erhalten werden "-".
Aufzähliger Typ
Das Aufzähliger Typ in c, angegeben mit dem enum
Schlüsselwort und oft nur als "Enum" bezeichnet (normalerweise ausgesprochen ee'-num /ˌI.nʌm/ oder Ee'-Noom /ˌI.nuːm/) ist ein Typ, der Werte in einer Reihe benannter Konstanten darstellt. Jeder der aufgezählten Konstanten hat einen Typ int
. Jeder enum
Typ selbst ist kompatibel mit char
oder einen signierten oder nicht signierten Ganzzahltyp, aber jede Implementierung definiert ihre eigenen Regeln für die Auswahl eines Typs.
Einige Compiler warnen, ob einem Objekt mit dem aufzähligen Typ einen Wert zugewiesen wird, der nicht einer seiner Konstanten ist. Einem solchen Objekt kann jedoch alle Werte im Bereich seines kompatiblen Typs zugewiesen werden, und enum
Konstanten können überall dort verwendet werden, wo eine Ganzzahl erwartet wird. Deshalb, enum
Werte werden häufig anstelle des Präprozessors verwendet #define
Richtlinien zur Schaffung benannter Konstanten. Solche Konstanten sind im Allgemeinen sicherer zu verwenden als Makros, da sie sich in einem bestimmten Identifikator -Namespace befinden.
Ein aufzähliger Typ wird mit dem deklariert enum
Spezifizierer und ein optionaler Name (oder Schild) für die Enum, gefolgt von einer Liste von einer oder mehreren Konstanten, die in lockigen Klammern enthalten und durch Kommas getrennt sind, und eine optionale Liste von Variablennamen. Nachfolgende Verweise auf einen bestimmten aufzähligen Typ verwenden die enum
Schlüsselwort und der Name des Enum. Standardmäßig wird der ersten Konstante in einer Aufzählung der Wert Null zugewiesen, und jeder nachfolgende Wert wird durch eine über die vorherige Konstante erhöht. Spezifische Werte können auch Konstanten in der Deklaration zugewiesen werden, und alle nachfolgenden Konstanten ohne spezifische Werte werden ab diesem Zeitpunkt inkrementierte Werte angegeben. Betrachten Sie beispielsweise die folgende Deklaration:
Auflauf Farben { ROT, GRÜN, BLAU = 5, GELB } Lackfarbe;
Dies erklärt das enum colors
Typ; das int
Konstanten RED
(deren Wert 0 ist), GREEN
(dessen Wert einer größer ist als RED
1), BLUE
(dessen Wert der angegebene Wert ist, 5) und YELLOW
(dessen Wert einer größer ist als BLUE
6); und die enum colors
Variable paint_color
. Die Konstanten können außerhalb des Kontextes der Aufzählung verwendet werden (wo ein ganzzahliger Wert zulässig ist), und andere Werte als die Konstanten können zugewiesen werden paint_color
, oder eine andere Variable des Typs enum colors
.
Schwimmende Punkttypen
Die Floating-Punkt-Form wird verwendet, um Zahlen mit einer fraktionalen Komponente darzustellen. Sie repräsentieren jedoch nicht genau die rationalen Zahlen; Sie sind stattdessen eine enge Annäherung. Es gibt drei Arten von realen Werten, die durch ihre Spezifizierer gekennzeichnet sind: Einzelgenauigkeit (float
), Doppelte Genauigkeit (double
) und doppelt erweiterte Präzision (long double
). Jeder von diesen kann Werte in einer anderen Form darstellen, oft eines der der IEEE Floating-Punkt Formate.
Typespezifizierer | Präzision (Dezimalstellen) | Exponent -Reichweite | ||
---|---|---|---|---|
Minimum | IEEE 754 | Minimum | IEEE 754 | |
float | 6 | 7,2 (24 Bit) | ± 37 | ± 38 (8 Bit) |
double | 10 | 15,9 (53 Bit) | ± 37 | ± 307 (11 Bit) |
long double | 10 | 34,0 (113 Bit) | ± 37 | ± 4931 (15 Bit) |
Schwimmpunktkonstanten können in geschrieben werden Dezimalschreibweise, z.B. 1.23
. Dezimale wissenschaftliche Notation Kann durch Hinzufügen verwendet werden e
oder E
gefolgt von einem Dezimaler seien auch als bekannt als als E Notation, z.B. 1.23e2
(der den Wert 1,23 × 10 hat2 = 123.0). Entweder ist ein Dezimalpunkt oder ein Exponent erforderlich (ansonsten wird die Zahl als Ganzzahlkonstante analysiert). Hexadezimale Schwimmpunktkonstanten Befolgen Sie ähnliche Regeln, außer dass sie durch vorangestellt werden müssen 0x
und verwenden p
oder P
um einen binären Exponenten anzugeben, z. 0xAp-2
(der den Wert 2.5 hat, seit ah × 2–2 = 10 × 2–2 = 10 ÷ 4). Sowohl dezimale als auch hexadezimale Schwimmpunktkonstanten können von satt, dass f
oder F
um eine Konstante des Typs anzuzeigen float
, durch l
(Buchstabe l
) oder L
zum Typ angeben long double
, oder links für a double
Konstante.
Die Standard -Header -Datei float.h
Definiert die minimalen und maximalen Werte der Gleitkomma-Typen der Implementierung float
, double
, und long double
. Es definiert auch andere Grenzen, die für die Verarbeitung von Gleitkomma-Zahlen relevant sind.
Speicherklassenspezifizierer
Jedes Objekt hat eine Speicherklasse. Dies gibt im Grunde genommen den Speicher an Dauer, Dies kann statisch sein (Standard für global), automatisch (Standard für lokal) oder dynamisch (zugeordnet) sowie andere Funktionen (Verknüpfung und Register -Hinweis).
Spezifizierer | Lebensdauer | Zielfernrohr | Standard -Initialisierer |
---|---|---|---|
auto | Block (Stack) | Block | Nicht initialisiert |
register | Block (Stack oder CPU -Register) | Block | Nicht initialisiert |
static | Programm | Block- oder Kompilierungseinheit | Null |
extern | Programm | Global (ganzes Programm) | Null |
(keiner)1 | Dynamisch (Haufen) | Nicht initialisiert (initialisiert zu 0 Wenn verwendet calloc() )) |
- 1 Zugewiesen und mit dem ausgegeben
malloc()
undfree()
Bibliotheksfunktionen.
In a deklarierte Variablen Block standardmäßig haben automatischen Speicher, ebenso wie diejenigen, die explizit mit dem deklariert sind auto
[2] oder register
Speicherklassenspezifizierer. Das auto
und register
Spezifizierer dürfen nur in Funktionen und Funktionen für Funktionsargumente verwendet werden. Als solche die auto
Der Spezifizierer ist immer überflüssig. Objekte, die außerhalb aller Blöcke deklariert sind und diejenigen, die ausdrücklich mit dem deklariert sind static
Speicherklassenspezifizierer haben eine statische Speicherdauer. Statische Variablen werden standardmäßig von der initialisiert Compiler.
Objekte mit automatischem Speicher sind lokal zu dem Block, in dem sie deklariert wurden, und werden beim Ausgang des Blocks verworfen. Zusätzlich wurden Objekte mit dem deklariert register
Die Speicherklasse kann vom Compiler für den Zugriff auf eine höhere Priorität erhalten Register; Obwohl der Compiler sich dafür entscheidet, keine davon in einem Register zu speichern. Objekte mit dieser Speicherklasse werden möglicherweise nicht mit der Adresse (Adresse (&
) Unary Operator. Objekte mit statischer Speicherung bestehen für die gesamte Dauer des Programms. Auf diese Weise kann auf das gleiche Objekt über mehrere Aufrufe hinweg zugegriffen werden. Objekte mit zugewiesener Speicherdauer werden ausdrücklich mit erstellt und zerstört mit malloc
, free
und verwandte Funktionen.
Das extern
Speicherklassespezifizierer zeigt an, dass der Speicher für ein Objekt an anderer Stelle definiert wurde. Wenn in einem Block verwendet wird, zeigt dies an, dass der Speicher durch eine Erklärung außerhalb dieses Blocks definiert wurde. Wenn es außerhalb aller Blöcke verwendet wird, zeigt dies an, dass der Speicher außerhalb der Kompilierungseinheit definiert wurde. Das extern
Speicherklassenspezifizierer ist überflüssig, wenn sie bei einer Funktionserklärung verwendet wird. Es zeigt an, dass die deklarierte Funktion außerhalb der Kompilierungseinheit definiert wurde.
Beachten Sie, dass Speicherspezifizierer nur für Funktionen und Objekte gelten. Andere Dinge wie Typ- und Enum -Erklärungen sind privat für die Kompilierungseinheit, in der sie erscheinen. Typen dagegen haben Qualifikationen (siehe unten).
Geben Sie Qualifikationen ein
Typen können qualifiziert werden, um spezielle Eigenschaften ihrer Daten anzuzeigen. Der Typ Qualifier Const
Zeigt an, dass sich ein Wert nicht ändert, sobald er initialisiert wurde. Versuch, a zu ändern Const
Der qualifizierte Wert liefert ein undefiniertes Verhalten, sodass einige C -Compiler sie speichern Rodata oder (für eingebettete Systeme) in Nur-Lese-Speicher (ROM). Der Typ Qualifier flüchtig
Zeigt auf an an Compiler optimieren dass es anscheinend nicht redundante Leads oder Schreibungen entfernen darf, da sich der Wert ändern kann, selbst wenn er nicht durch Ausdruck oder Aussage geändert wurde, oder mehrere Schreibvorgänge erforderlich sein können, wie z. B. für Speicher-abgebildete I/O.
Unvollständige Typen
Ein unvollständiger Typ ist a Struktur oder Vereinigung Typ, dessen Mitglieder noch nicht spezifiziert wurden, und Array -Typ deren Dimension wurde noch nicht angegeben oder die void
Schreib die void
Typ kann nicht abgeschlossen werden). Ein solcher Typ darf nicht instanziiert werden (seine Größe ist nicht bekannt), und es dürfen auch nicht auf seine Mitglieder zugegriffen werden (auch sie sind unbekannt); Der abgeleitete Zeigertyp kann jedoch verwendet werden (aber nicht Derferenziert).
Sie werden oft mit Zeigern verwendet, entweder als Vorwärts- oder externe Erklärungen. Zum Beispiel könnte Code einen unvollständigen Typ wie diesen erklären:
Struktur Ding *pt;
Dies erklärt pt
als Zeiger auf struct thing
und der unvollständige Typ struct thing
. Zeiger auf Daten haben immer die gleiche Byte-Breite, unabhängig davon, worauf sie hinweisen pt
ist nicht Derferenziert). Der unvollständige Typ kann später im selben Bereich abgeschlossen werden, indem er ihn neu klagt:
Struktur Ding { int num; }; / * Ding Struct Type ist jetzt abgeschlossen */
Unvollständige Typen werden zur Implementierung verwendet rekursiv Strukturen; Der Körper der Typdeklaration kann später in der Übersetzungseinheit verschoben werden:
Typedef Struktur Bert Bert; Typedef Struktur Wilma Wilma; Struktur Bert { Wilma *Wilma; }; Struktur Wilma { Bert *Bert; };
Unvollständige Typen werden auch für verwendet Daten verstecken; Der unvollständige Typ ist in a definiert Header-Dateiund der Körper nur innerhalb der entsprechenden Quelldatei.
Zeiger
In Deklarationen der Sternchenmodifikator (*
) Gibt einen Zeigertyp an. Zum Beispiel wo der Spezifizierer int
würde sich auf den Ganzzahltyp beziehen, den Spezifizierer int*
Bezieht sich auf den Typ "Zeiger auf Ganzzahl". Zeigerwerte verbinden zwei Informationen: eine Speicheradresse und einen Datentyp. Die folgende Codezeile deklariert eine Variable Zeiger-in-i-Intener-Variable ptr:
int *ptr;
Referenzierung
Wenn ein nicht statischer Zeiger deklariert wird, hat er einen nicht spezifizierten Wert zugeordnet. Die mit einem solchen Zeiger verbundene Adresse muss vor der Verwendung durch Zuordnung geändert werden. Im folgenden Beispiel, ptr wird so eingestellt, dass es auf die mit der Variablen verknüpften Daten zeigt a:
int a = 0; int *ptr = &a;
Um dies zu erreichen &
) wird genutzt. Es erzeugt den Speicherort des folgenden Datenobjekts.
Derference
Auf die spitzen Daten können über einen Zeigerwert zugegriffen werden. Im folgenden Beispiel die Ganzzahlvariable b wird auf den Wert der Ganzzahlvariablen eingestellt a, was 10 ist:
int a=10; int *p; p = &a; int b = *p;
Um diese Aufgabe zu erfüllen, ist der Unär Dereference -Operator, bezeichnet durch ein Sternchen (*), wird verwendet. Es gibt die Daten zurück, zu denen sein Operand - das aus Zeigertyp sein muss - Punkte. Somit der Ausdruck *p bezeichnet den gleichen Wert wie a. Dereferencing a Null Zeiger ist illegal.
Arrays
Array -Definition
Arrays werden in C verwendet, um Strukturen aufeinanderfolgender Elemente desselben Typs darzustellen. Die Definition eines (festen Größe) Array hat die folgende Syntax:
int Array[100];
was ein Array namens definiert Array 100 Werte des primitiven Typs halten int
. Wenn die Array-Dimension in einer Funktion deklariert wird, kann sie auch eine nicht konstante Expression sein. In diesem Fall wird der Speicher für die angegebene Anzahl von Elementen zugewiesen. In den meisten späteren Kontexten wird eine Erwähnung der Variablen erwähnt Array wird in einen Zeiger auf das erste Element im Array konvertiert. Das sizeof
Der Bediener ist eine Ausnahme: sizeof array
ergibt die Größe des gesamten Arrays (dh 100 -mal so groß wie eine int
, und sizeof(array) / sizeof(int)
wird 100 zurückkehren). Eine weitere Ausnahme ist der Operator & (Adresse), der zum Beispiel einen Zeiger auf das gesamte Array ergibt
int (*ptr_to_array) [100] = &Array;
Zugriff auf Elemente
Die primäre Einrichtung für den Zugriff auf die Werte der Elemente eines Arrays ist der Array -Indexbetreiber. Zugreifen auf die i-Idexed Element von Arraydie Syntax wäre array[i]
, was sich auf den Wert bezieht, der in diesem Array -Element gespeichert ist.
Die Array -Indexnummerierung beginnt bei 0 (siehe Zero-basierte Indexierung). Das größte zulässige Array -Index ist daher gleich der Anzahl der Elemente im Array minus 1. Um dies zu veranschaulichen, betrachten Sie ein Array a als 10 Elemente deklariert; Das erste Element wäre a[0]
Und das letzte Element wäre a[9]
.
C bietet keine Einrichtung für automatisch Grenzenprüfung Für die Array -Nutzung. Obwohl logisch das letzte Index in einem Array von 10 Elementen 9 sein würde, könnte der Index 10, 11 usw. versehentlich mit undefinierten Ergebnissen angegeben werden.
Aufgrund der austauschbaren Arrays und Zeiger können die Adressen der einzelnen Array -Elemente gleichwertig ausgedrückt werden Zeigerarithmetik. Die folgende Tabelle zeigt beide Methoden für das vorhandene Array:
Element | Zuerst | Zweite | Dritte | nth |
---|---|---|---|---|
Array -Index | array[0] | array[1] | array[2] | array[n - 1] |
Derferender Zeiger | *array | *(array + 1) | *(array + 2) | *(array + n - 1) |
Seit dem Ausdruck a[i]
ist semantisch äquivalent zu *(a+i)
, was wiederum gleich ist *(i+a)
Der Ausdruck kann auch als geschrieben werden i[a]
, obwohl diese Form selten verwendet wird.
Arrays variabler Länge
C99 standardisiert Arrays variabler Länge (VLAS) innerhalb des Blockbereichs. Solche Array -Variablen werden auf der Grundlage des Werts eines Ganzzahlwerts zur Laufzeit nach dem Eintritt in einen Block zugeteilt und am Ende des Blocks behandelt.[3] Ab C11 Diese Funktion muss vom Compiler nicht mehr implementiert werden.
int n = ...; int a[n]; a[3] = 10;
Diese Syntax erzeugt ein Array, dessen Größe bis zum Ende des Blocks festgelegt ist.
Dynamische Arrays
Arrays, die dynamisch geändert werden können, können mit Hilfe des C Standardbibliothek. Das Malloc
Die Funktion bietet eine einfache Methode zur Zuweisung von Speicher. Es braucht einen Parameter: die Speichermenge, um Bytes zuzuweisen. Nach erfolgreicher Zuordnung, malloc
Gibt ein Generikum zurück (void
) Zeigerwert, auf den Beginn des zugewiesenen Raums hinweisen. Der zurückgegebene Zeigerwert wird implizit durch Zuweisung in einen geeigneten Typ konvertiert. Wenn die Zuweisung nicht abgeschlossen sein könnte, malloc
Gibt eine zurück Null Zeiger. Das folgende Segment ist daher in der Funktion der oben genannten Deklaration ähnlich:
#enthalten / * deklariert malloc */ ... int *a = Malloc(n * Größe von *a); a[3] = 10;
Das Ergebnis ist ein "Zeiger auf int
"Variable (a) Das zeigt auf den ersten von n zusammenhängend int
Objekte; Aufgrund der Array -Pointer -Äquivalenz kann dies anstelle eines tatsächlichen Array -Namens verwendet werden, wie in der letzten Zeile gezeigt. Der Vorteil bei der Verwendung dieser dynamische Zuweisung ist, dass die Menge an Speicher, die ihm zugeordnet ist realloc
).
Wenn der dynamisch zugeordnete Speicher nicht mehr benötigt wird, sollte er wieder in das Laufzeitsystem freigegeben werden. Dies geschieht mit einem Anruf an die free
Funktion. Es benötigt einen einzelnen Parameter: einen Zeiger auf zuvor zugewiesene Speicher. Dies ist der Wert, der durch einen früheren Anruf an zurückgegeben wurde malloc
.
Als Sicherheitsmaßnahme einige Programmierer[wer?] Setzen Sie dann die Zeigervariable auf NULL
:
frei(a); a = NULL;
Dies stellt sicher, dass weitere Versuche, den Zeiger auf den meisten Systemen zu Dereference, das Programm zum Absturz bringen. Wenn dies nicht erledigt ist, wird die Variable a baumelnder Zeiger Dies kann zu einem nutzungsfreien Fehler führen. Wenn der Zeiger jedoch eine lokale Variable ist, setzen Sie ihn auf NULL
verhindert nicht, dass das Programm andere Kopien des Zeigers verwendet. Lokale Nutzungsfehler sind normalerweise einfach Statische Analysatoren erkennen. Daher ist dieser Ansatz für lokale Zeiger weniger nützlich und wird häufiger mit Zeigern verwendet, die in langlebigen Strukturen gespeichert sind. Im Allgemeinen jedoch, um Zeiger auf NULL
ist gute Praxis[Nach wem?] wie es es zulässt, ist ein Programmierer NULL
-Überprüfen Sie die Hinweise vor der Derference, wodurch Unfälle verhindert werden.
Wenn man sich an das Array-Beispiel angerufen hat, könnte man auch ein Array fester Größe durch dynamische Zuordnung erstellen:
int (*a) [100] = Malloc(Größe von *a);
... was einen Zeiger auf Array ergibt.
Der Zugriff auf den Zeiger-zu-Array kann auf zwei Arten erfolgen:
(*a) [Index]; Index[*a];
Das Iterieren kann auch auf zwei Arten durchgeführt werden:
zum (int i = 0; i < 100; i++) (*a) [i]; zum (int *i = a[0]; i < a[1]; i++) *i;
Der Vorteil der Verwendung des zweiten Beispiels besteht darin, dass die numerische Grenze des ersten Beispiels nicht erforderlich ist, was bedeutet, dass der Zeiger-auf-Array jede Größe und das zweite Beispiel ohne Änderungen ausführen kann.
Mehrdimensionale Arrays
Darüber hinaus unterstützt C Arrays mehrerer Dimensionen, die in gespeicherten Abmessungen gespeichert sind Reihen-Major-Bestellung. Technisch gesehen handelt es sich um mehrdimensionale C-Arrays, nur eindimensionale Arrays, deren Elemente Arrays sind. Die Syntax zur Deklarierung mehrdimensionaler Arrays lautet wie folgt:
int Array2d[REIHEN][SÄULEN];
wo REIHEN und SÄULEN sind Konstanten. Dies definiert ein zweidimensionales Array. Lesen Sie die Unterläufe von links nach rechts, Array2d ist eine Reihe von Länge REIHEN, jedes Element, das ein Array von ist SÄULEN Ganzzahlen.
Um in diesem mehrdimensionalen Array auf ein ganzzahliges Element zuzugreifen, würde man verwenden
Array2d[4][3]
Nochmals, wenn Sie von links nach rechts lesen, greift dies auf die 5. Zeile und das 4. Element in dieser Zeile zu. Der Ausdruck array2d[4]
ist ein Array, das wir dann mit [3] abonnieren, um auf die vierte Ganzzahl zuzugreifen.
Element | Zuerst | Zweite Reihe, zweite Spalte | iWurf, jTH -Säule |
---|---|---|---|
Array -Index | array[0][0] | array[1][1] | array[i - 1][j - 1] |
Derferender Zeiger | *(*(array + 0) + 0) | *(*(array + 1) + 1) | *(*(array + i - 1) + j - 1) |
Höherdimensionale Arrays können auf ähnliche Weise deklariert werden.
Ein mehrdimensionales Array sollte nicht mit einer Reihe von Referenzen auf Arrays verwechselt werden (auch als als bekannt als ein Iliffe Vector oder manchmal ein Array von Arrays). Ersteres ist immer rechteckig (alle Subarrays müssen gleich groß sein) und nimmt einen zusammenhängenden Gedächtnisbereich ein. Letzteres ist ein eindimensionales Array von Zeigern, von denen jedes auf das erste Element eines Subarrays an einem anderen Ort im Gedächtnis hinweist, und die Sub-Arrays müssen nicht die gleiche Größe haben. Letzteres kann durch mehrere Verwendungen von erstellt werden malloc
.
Saiten
In C sind Streichliterale von Doppelzitaten umgeben (umgeben"
), z.B. "Hello world!"
und werden mit einem Array der angegebenen zusammengestellt char
Werte mit zusätzlich NULL -Beendetcharakter (0-bewertet) Code, um das Ende der Zeichenfolge zu markieren.
String -Literale dürfen keine eingebetteten Newlines enthalten; Dieses Verbot vereinfacht die Parsen der Sprache etwas. Um eine neue Linie in eine Zeichenfolge aufzunehmen, die Backslash -Flucht \n
kann wie unten verwendet werden.
Es gibt mehrere Standardbibliotheksfunktionen für den Betrieb mit String -Daten (nicht unbedingt konstant), die als Array von organisiert sind char
Verwenden dieses null-terminierten Formats; sehen unter.
Die String-Literal-Syntax von C war sehr einflussreich und hat sich in viele andere Sprachen wie C ++, Objective-C, Perl, Python, PHP, Java, JavaScript, C#, Ruby eingeleitet. Heutzutage übernehmen oder bauen fast alle neuen Sprachen auf die String-Syntax im C-Stil. Sprachen, denen diese Syntax fehlt, neigen dazu, C vor C. vorzugehen.
Backslash entkommt
Da bestimmte Zeichen nicht direkt Teil eines buchstäblichen String -Ausdrucks sein können, werden sie stattdessen durch eine Escape -Sequenz identifiziert, die mit einem Backslash beginnt (\
). Zum Beispiel die Backslashes in "This string contains \"double quotes\"."
Geben Sie (zum Compiler) an, dass das innere Zitatpaar eher als tatsächlicher Teil der Zeichenfolge gedacht ist als der Standardwertlesen als Trennzeichen (Endpunkt) der Zeichenfolge selbst.
Backslashes können verwendet werden, um verschiedene Steuerzeichen usw. in eine Zeichenfolge einzugeben:
Flucht | Bedeutung |
---|---|
\\ | Buchstäblicher Backglash |
\" | Doppelzitat |
\' | Single Zitat |
\n | Newline (Zeilenfutter) |
\r | Kutschenrückkehr |
\b | Rücktaste |
\t | Horizontale Registerkarte |
\f | Formfutter |
\a | Alarm (Glocke) |
\v | Vertikale Registerkarte |
\? | Fragezeichen (verwendet, um zu entkommen Trigraphen)) |
%% | Prozentsatz, prozentuale Marke, Printf -Format -Saiten Nur (Hinweis \% ist nicht Standard und nicht immer erkannt) |
\ Ooo | Charakter mit Oktalwert Ooo (wo Ooo ist 1-3 Oktalstellen, '0'-'7') |
\ xhh | Charakter mit Hexadezimalwert HH (wo HH ist 1 oder mehr Hex-Ziffern, '0'-'9', 'a'-'f', 'a'-'f') |
Die Verwendung anderer Backslash -Flucht wird nicht vom C -Standard definiert, obwohl Compiler -Anbieter häufig zusätzliche Fluchtcodes als Sprachverlängerungen bereitstellen. Eine davon ist die Fluchtsequenz \ e
für die Escape-Zeichen mit ASCII -HEX -Wert 1b, der dem C -Standard nicht hinzugefügt wurde, da es keine Darstellung in anderen Zeichensätze (wie zum Beispiel Ebcdic). Es ist in erhältlich in GCC, Klang und tcc.
String buchstäbliche Verkettung
C hat String buchstäbliche Verkettung, was bedeutet, dass benachbarte String -Literale zur Kompilierungszeit verkettet werden; Dadurch können lange Saiten über mehrere Zeilen geteilt werden und ermöglicht auch String -Literale, die aus resultieren C Präprozessor Definiert und Makros, die zur Kompilierung an Strings angehängt werden sollen:
printf(__DATEI__ ": %d: Hallo" "Welt\n", __LINIE__);
wird auf expandieren
printf("HelloWorld.c" ": %d: Hallo" "Welt\n", 10);
das ist syntaktisch äquivalent zu
printf("HelloWorld.c: %d: Hallo Welt\n", 10);
Charakterkonstanten
Einzelne Charakterkonstanten sind einzeln zitierte, z. 'A'
, und type haben int
(in C ++, char
). Der Unterschied ist das "A"
repräsentiert ein null-terminiertes Array von zwei Zeichen, 'a' und '\ 0', während 'A'
repräsentiert direkt den Zeichenwert (65, wenn ASCII verwendet wird). Die gleichen Backslash-Escapes werden wie bei Saiten unterstützt, außer dass (natürlich) "
kann gültig als Charakter verwendet werden, ohne entkommen zu werden, während '
muss jetzt entkommen werden.
Eine Charakterkonstante kann nicht leer sein (d.h. ''
ist ungültige Syntax), obwohl eine Zeichenfolge sein kann (es hat immer noch das Null -enden -Zeichen). Multi-Charakter-Konstanten (z. 'xy'
) sind gültig, obwohl selten nützlich-sie lassen einen Zeichen in einer Ganzzahl mehrere Zeichen (z. B. 4 ASCII-Zeichen können in eine 32-Bit-Ganzzahl passen, 8 in einem 64-Bit). Da die Reihenfolge, in der die Charaktere in eine gepackt sind int
Es ist nicht angegeben (zur Definition der Implementierung gelassen), tragbare Verwendung von Multi-Charakter-Konstanten ist schwierig.
In Situationen, die auf eine bestimmte Plattform und die Compiler -Implementierung beschränkt sind, finden Multicharacter -Konstanten ihre Verwendung bei der Angabe von Signaturen. Ein gemeinsamer Anwendungsfall ist der Ostype, wo die Kombination klassischer Mac OS-Compiler und seiner inhärenten Bigendianess bedeutet, dass Bytes in der Ganzzahl in der genauen Reihenfolge der im wörtlichen definierten Zeichen erscheinen. Die Definition durch populäre "Implementierungen" ist tatsächlich konsistent: in GCC, Clang und Visuell c ++, '1234'
ergibt 0x31323334
unter ASCII.[5][6]
Breite Charakter -Saiten
Seit Typ char
ist 1 byte breit, ein einzeln char
Wert kann normalerweise höchstens 255 unterschiedliche Zeichencodes darstellen, nicht annähernd genug für alle weltweit verwendeten Zeichen. Um internationale Charaktere besser zu unterstützen, wurde der erste C -Standard (C89) eingeführt breite Charaktere (codiert in Typ wchar_t
) und breite Zeichenzeichenfolgen, die als geschrieben werden als L"Hello world!"
Breite Zeichen sind am häufigsten entweder 2 Bytes (unter Verwendung einer 2-Byte-Codierung wie z. UTF-16) oder 4 Bytes (normalerweise UTF-32), aber Standard C gibt die Breite nicht an für wchar_t
die Wahl dem Implementierer überlassen. Microsoft Windows Verwendet im Allgemeinen UTF-16, daher wäre die obige Zeichenfolge 26 Bytes lang für einen Microsoft-Compiler. das Unix Welt bevorzugt UTF-32, so dass Compiler wie GCC eine 52-Byte-Zeichenfolge erzeugen würden. Eine 2-Byte-Breite wchar_t
erleidet die gleiche Einschränkung wie char
, in diesen bestimmten Charakteren (die außerhalb der Bmp) kann nicht in einem einzigen dargestellt werden wchar_t
; muss aber verwendet werden Ersatzpaare.
Der ursprüngliche C -Standard spezifizierte nur minimale Funktionen für den Betrieb mit breiten Zeichenzeichenfolgen; 1995 wurde der Standard so geändert char
Saiten. Die relevanten Funktionen sind hauptsächlich nach ihrem benannt char
Äquivalente mit Zugabe eines "W" oder dem Ersatz von "STR" durch "WCS"; Sie sind in angegeben
, mit
Enthaltende Klassifizierungs- und Kartierungsfunktionen mit breitem Charakter.
Die jetzt allgemein empfohlene Methode[7] von internationalen Charakteren zu unterstützen, ist durch UTF-8, was gespeichert ist in char
Arrays und können direkt in den Quellcode geschrieben werden, wenn ein UTF-8-Editor verwendet wird, da UTF-8 direkt ist ASCII -Erweiterung.
Variable Breite
Eine gemeinsame Alternative zu wchar_t
ist eine Verwendung a Codierung der variablen Breite, wobei ein logisches Zeichen über mehrere Positionen der Zeichenfolge erstreckt wird. Variable Breitenzeichenfolgen können in Literale wörtlich codiert werden, auf das Risiko, den Compiler zu verwirren oder numerische Backslash-Flucht zu verwenden (z. "\xc3\xa9"
für "é" in UTF-8). Das UTF-8 Codierung wurde speziell entwickelt (unter Plan 9) für die Kompatibilität mit den Standardbibliothekszeichenfolge; Zu den unterstützenden Merkmalen der Codierung gehören ein Mangel an eingebetteten Nulls, keine gültigen Interpretationen für Subsequenzen und eine triviale Resynchronisierung. Codierungen, denen diese Merkmale fehlen, sind wahrscheinlich mit den Standardbibliotheksfunktionen nicht kompatibel. In solchen Fällen werden häufig kodierende Zeichenfolgenfunktionen verwendet.
Bibliotheksfunktionen
Saitensowohl konstante als auch variable können manipuliert werden, ohne die zu verwenden Standardbibliothek. Die Bibliothek enthält jedoch viele Nützliche Funktionen zur Arbeit mit null-terminierten Saiten.
Strukturen und Gewerkschaften
Strukturen
Strukturen und Gewerkschaften In C werden Datencontainer definiert, die aus einer Abfolge benannter Mitglieder verschiedener Typen bestehen. Sie ähneln den Aufzeichnungen in anderen Programmiersprachen. Die Mitglieder einer Struktur werden an aufeinanderfolgenden Stellen im Speicher gespeichert, obwohl der Compiler die Polsterung zwischen oder nach den Mitgliedern (jedoch nicht vor dem ersten Mitglied) zur Effizienz oder als Polsterung einfügen darf Ausrichtung durch die Zielarchitektur. Die Größe einer Struktur entspricht der Summe der Größen ihrer Mitglieder sowie der Größe der Polsterung.
Gewerkschaften
Die Gewerkschaften in C sind mit Strukturen zusammenhängen und als Objekte definiert, die (zu unterschiedlichen Zeiten) Objekten verschiedener Typen und Größen enthalten können. Sie sind analog zu Variantendatensätzen in anderen Programmiersprachen. Im Gegensatz zu Strukturen beziehen sich die Komponenten einer Vereinigung alle auf denselben Ort im Speicher. Auf diese Weise kann eine Vereinigung zu verschiedenen Zeiten verwendet werden, um verschiedene Arten von Objekten zu halten, ohne dass für jeden neuen Typ ein separates Objekt erstellt werden musste. Die Größe einer Vereinigung entspricht der Größe ihres größten Komponententyps.
Erklärung
Strukturen werden mit dem deklariert struct
Schlüsselwort und Gewerkschaften werden mit dem deklariert union
Stichwort. Auf das Schlüsselwort des Spezifizierers folgt ein optionaler Bezeichner -Name, der verwendet wird, um die Form der Struktur oder Vereinigung zu identifizieren. Auf die Kennung folgt die Erklärung der Struktur oder der Einstellung der Gewerkschaft: eine Liste der Mitgliedererklärungen, die in lockigen Klammern enthalten sind, wobei jede Erklärung von einem Semikolon gekündigt wird. Schließlich schließt die Erklärung mit einer optionalen Liste von Kennungsnamen, die als Instanzen der Struktur oder Gewerkschaft deklariert werden.
Beispielsweise deklariert die folgende Erklärung eine Struktur namens namens s
das enthält drei Mitglieder; Es wird auch eine Instanz der als als bekannten Struktur erklären, die als bekannt ist tee
:
Struktur s { int x; schweben y; verkohlen *z; } T -Shirt;
Und die folgende Erklärung wird eine ähnliche Gewerkschaft benannt erklären u
und eine Instanz davon namens genannt n
:
Union u { int x; schweben y; verkohlen *z; } n;
Mitglieder von Strukturen und Gewerkschaften können keinen unvollständigen oder Funktionstyp haben. Daher können Mitglieder kein Beispiel dafür sein, dass die Struktur oder Gewerkschaft deklariert wird (weil sie zu diesem Zeitpunkt unvollständig ist), kann jedoch Zeiger auf den Typ sein, der deklariert wird.
Sobald eine Struktur oder ein Gewerkschaftskörper deklariert und einen Namen gegeben wurde, kann sie als neuer Datentyp unter Verwendung des Spezifizierers angesehen werden struct
oder union
gegebenenfalls und der Name. Beispielsweise deklariert die folgende Erklärung bei der obigen Strukturerklärung eine neue Instanz der Struktur s
genannt r
:
Struktur s r;
Es ist auch üblich, die zu verwenden Typedef
Spezifizierer, um die Notwendigkeit der Notwendigkeit zu beseitigen struct
oder union
Schlüsselwort in späteren Verweisen auf die Struktur. Die erste Bezeichnung nach dem Körper der Struktur wird als neuer Name für den Strukturtyp angesehen (Strukturinstanzen werden in diesem Zusammenhang möglicherweise nicht deklariert). Zum Beispiel wird die folgende Erklärung einen neuen Typ, der als bekannt ist s_type Das enthält eine Struktur:
Typedef Struktur {...} s_type;
Zukünftige Aussagen können dann den Spezifizierer verwenden s_type (statt der erweiterten struct
... Spezifizierer), um auf die Struktur zu verweisen.
Zugriff auf Mitglieder
Die Mitglieder werden unter Verwendung des Namens der Instanz einer Struktur oder Gewerkschaft, einer Zeit (Zeit.
) und der Name des Mitglieds. Zum Beispiel angesichts der Erklärung von T -Shirt von oben, das bekannt bekannte Mitglied als y (vom Typ float
) kann mit der folgenden Syntax zugegriffen werden:
T -Shirt.y
Strukturen werden üblicherweise über Zeiger zugegriffen. Betrachten Sie das folgende Beispiel, das einen Zeiger definiert T -Shirt, bekannt als ptr_to_tee:
Struktur s *ptr_to_tee = &T -Shirt;
Mitglied y von T -Shirt kann dann durch Dereferenzierung zugänglich sein ptr_to_tee und mit dem Ergebnis als linker Operanden:
(*ptr_to_tee).y
Was identisch mit dem einfacheren ist tee.y
darüber hinaus ptr_to_tee verweist auf T -Shirt. Wegen Vorrang ("." höher als "*"), desto kürzer *ptr_to_tee.y
ist für diesen Zweck falsch und wird stattdessen als analysiert *(ptr_to_tee.y)
und so sind die Klammern notwendig. Da diese Operation üblich ist, bietet C a abgekürzte Syntax Für den Zugriff auf ein Mitglied direkt von einem Zeiger. Mit dieser Syntax wird der Name der Instanz durch den Namen des Zeigers ersetzt und die Periode durch die Zeichensequenz ersetzt ->
. Somit die folgende Methode zum Zugriff y ist identisch mit den beiden vorherigen:
ptr_to_tee->y
Mitglieder der Gewerkschaften sind auf die gleiche Weise zugegriffen.
Dies kann angekettet werden; In einer verknüpften Liste kann man sich beispielsweise beziehen N-> Weiter-> Weiter
für den zweiten folgenden Knoten (unter der Annahme dessen N-> Weiter
ist nicht null).
Abtretung
Das Zuweisen von Werten an einzelne Mitglieder von Strukturen und Gewerkschaften ist syntaktisch identisch mit dem Zuweisen von Werten jedem anderen Objekt. Der einzige Unterschied ist, dass die lvalue der Zuordnung ist der Name des Mitglieds, auf die die oben erwähnte Syntax zugegriffen wird.
Eine Struktur kann auch als Einheit einer anderen Struktur desselben Typs zugeordnet werden. Strukturen (und Zeiger auf Strukturen) können auch als Funktionsparameter und Rückgabetypen verwendet werden.
Beispielsweise weist die folgende Anweisung dem Namen des Namens den Wert von 74 (den ASCII -Codepunkt für den Buchstaben 't') zu x in der Struktur T -Shirt, von oben:
T -Shirt.x = 74;
Und die gleiche Zuordnung, verwenden ptr_to_tee anstelle von T -Shirt, würde aussehen wie:
ptr_to_tee->x = 74;
Die Zuordnung mit Gewerkschaftsmitgliedern ist identisch.
Andere Operationen
Gemäß dem C-Standard kopieren die einzigen juristischen Operationen, die auf einer Struktur ausgeführt werden können, und weisen Sie sie als Einheit (oder initialisieren) zu, und nehmen Sie seine Adresse mit der Adresse (Adresse (&
) Unärer Betreiber und Zugriff auf seine Mitglieder. Gewerkschaften haben die gleichen Einschränkungen. Einer der Operationen implizit verboten ist, ist der Vergleich: Strukturen und Gewerkschaften können nicht unter Verwendung von C -Standardvergleichsanlagen verglichen werden (==
, >
, <
, etc.).
Bitfelder
C bietet auch eine spezielle Art von Strukturmitglied, die als a bekannt ist Bitfeld, was eine Ganzzahl mit einer explizit angegebenen Anzahl von Bits ist. Ein Bitfeld wird als Strukturmitglied des Typs deklariert int
, signed int
, unsigned int
, oder _Bool
, folgt dem Mitgliedsnamen durch einen Dickdarm (:
) und die Anzahl der Bits sollte es besetzen. Die Gesamtzahl der Bits in einem einzigen Bitfeld darf die Gesamtzahl der Bits in seinem deklarierten Typ nicht überschreiten.
Als besondere Ausnahme von den üblichen C-Syntaxregeln ist es implementiert, ob ein Bitfeld als Typ deklariert wurde int
ohne Angabe signed
oder unsigned
, ist signiert oder nicht signiert. Somit wird empfohlen, explizit festzulegen signed
oder unsigned
auf allen Strukturmitgliedern zur Portabilität.
Unbenannte Felder, die nur aus einem Dickdarm bestehen, gefolgt von einer Reihe von Bits sind ebenfalls zulässig; diese zeigen an Polsterung. Die Angabe einer Breite von Null für ein namenloses Feld wird verwendet, um zu erzwingen Ausrichtung zu einem neuen Wort.[8]
Die Mitglieder von Bit Fields haben keine Adressen und können als solche nicht mit der Adresse der Adresse verwendet werden ((&
) Unary Operator. Das sizeof
Der Bediener darf nicht auf Bitfelder angewendet werden.
Die folgende Erklärung deklariert einen neuen Strukturart, der als bekannt ist f
und eine Instanz davon als bekannt als als g
. Kommentare geben eine Beschreibung der einzelnen Mitglieder an:
Struktur f { ohne Vorzeichen int Flagge : 1; / * Ein Bitflag: Kann entweder auf (1) oder aus (0) */sein unterzeichnet int num : 4; /* ein signiertes 4-Bit-Feld; Bereich -7 ... 7 oder -8 ... 7 */ unterzeichnet int : 3; / * 3 Bit Polster, um 8 Bit zu runden */ } g;
Initialisierung
Die Standardinitialisierung hängt von der ab Speicherklassenspezifizierer, oben beschrieben.
Aufgrund der Grammatik der Sprache kann ein skalarer Initialisierer in einer beliebigen Anzahl von lockigen Klammerpaaren eingeschlossen sein. Die meisten Compiler geben jedoch eine Warnung aus, wenn es jedoch mehr als ein solches Paar gibt.
int x = 12; int y = { 23 }; // legal, keine Warnung int z = { { 34 } }; // legal, erwarten Sie eine Warnung
Strukturen, Gewerkschaften und Arrays können in ihren Deklarationen unter Verwendung einer Initialisiererliste initialisiert werden. Sofern keine Bezeichner verwendet werden, entsprechen die Komponenten eines Initialisierers den Elementen in der Reihenfolge, in der sie definiert und gespeichert sind. Daher müssen alle vorhergehenden Werte vor dem Wert eines bestimmten Elements bereitgestellt werden. Alle nicht spezifizierten Elemente sind auf Null gesetzt (mit Ausnahme von Gewerkschaften). Die Erwähnung zu viele Initialisierungswerte ergibt einen Fehler.
In der folgenden Erklärung wird eine neue Instanz der Struktur initialisiert s bekannt als Pi:
Struktur s { int x; schweben y; verkohlen *z; }; Struktur s Pi = { 3, 3.1415, "Pi" };
Bezeichnete Initialisierer
Die ausgewiesenen Initialisierer ermöglichen es den Mitgliedern, in jeder Reihenfolge und ohne explizit die vorhergehenden Werte mit Namen initialisiert zu werden. Die folgende Initialisierung entspricht der vorherigen:
Struktur s Pi = { .z = "Pi", .x = 3, .y = 3.1415 };
Durch die Verwendung eines Bezeichners in einem Initialisierer bewegt sich die Initialisierung "Cursor". Im folgenden Beispiel, wenn Max
ist größer als 10, es wird in der Mitte einige Null-Wert-Elemente geben a
; Wenn es weniger als 10 ist, werden einige der von den ersten fünf Initialisierern bereitgestellten Werte von den zweiten fünf überschrieben (wenn Max
ist weniger als 5, es wird einen Kompilierungsfehler geben):
int a[Max] = { 1, 3, 5, 7, 9, [Max-5] = 8, 6, 4, 2, 0 };
Im C89Eine Gewerkschaft wurde mit einem einzigen Wert initialisiert, der auf ihr erstes Mitglied angewendet wurde. Das heißt, die Gewerkschaft u oben definiert konnte nur seine haben int x Mitglied initialisiert:
Union u Wert = { 3 };
Mit einem ausgewiesenen Initialisierer muss das zu initialisierte Mitglied nicht das erste Mitglied sein:
Union u Wert = { .y = 3.1415 };
Wenn ein Array eine unbekannte Größe hat (d. H. Das Array war ein unvollständiger Typ) Die Anzahl der Initialisierer bestimmt die Größe des Arrays und sein Typ wird vollständig:
int x[] = { 0, 1, 2 } ;
Verbunddesignatoren können verwendet werden, um eine explizite Initialisierung zu liefern, wenn einheitliche Initialisiererlisten möglicherweise missverstanden werden. Im folgenden Beispiel, w
wird als eine Reihe von Strukturen deklariert, wobei jede Struktur aus einem Mitglied besteht a
(eine Reihe von 3 int
) und ein Mitglied b
(ein int
). Der Initialisierer legt die Größe von fest w
auf 2 und legt die Werte des ersten Elements ein a
:
Struktur { int a[3], b; } w[] = { [0].a = {1}, [1].a[0] = 2 };
Dies entspricht:
Struktur { int a[3], b; } w[] = { { { 1, 0, 0 }, 0 }, { { 2, 0, 0 }, 0 } };
Es gibt keine Möglichkeit, die Wiederholung eines Initialisierers in Standard C anzugeben.
Zusammengesetzte Literale
Es ist möglich, die Initialisierungsmethode auszuleihen, um zusammengesetzte Struktur und Array -Literale zu erzeugen:
// Zeiger aus Array buchstäblich. int *ptr = (int[]) { 10, 20, 30, 40 }; // Zeiger auf Array. schweben (*Foo) [3] = &(schweben[]) { 0,5f, 1.f, -0.5f }; Struktur s Pi = (Struktur s) { 3, 3.1415, "Pi" };
Verbunde Literale werden häufig mit festgelegten Initialisierern kombiniert, um die Erklärung lesbarer zu gestalten:[3]
Pi = (Struktur s) { .z = "Pi", .x = 3, .y = 3.1415 };
Betreiber
Kontrollstrukturen
C ist a Freiformsprache.
Verspannungsstil variiert zwischen Programmierer zum Programmierer und kann Gegenstand der Debatte sein. Sehen Eingerichteter Stil für mehr Details.
Zusammengesetzte Aussagen
In den Elementen in diesem Abschnitt kann jeder <Anweisung> durch a ersetzt werden Zusammengesetzte Aussage. Zusammengesetzte Aussagen haben die Form:
{ <Optional-Erklärung-aufführen> <Optional-Aussage-aufführen> }
und werden als Körper einer Funktion oder überall, wo eine einzige Aussage erwartet wird, verwendet. Die Deklarationsliste erklärt, dass Variablen darin verwendet werden sollen Umfang, und die Statement-Liste sind die Maßnahmen, die auszuführen sind. Klammern definieren ihren eigenen Umfang, und in diesen Klammern definierte Variablen werden automatisch in der Schlussklasse versehen. Deklarationen und Aussagen können innerhalb einer zusammengesetzten Aussage frei vermischt werden (wie in C ++).
Auswahlanweisungen
C hat zwei Arten von Auswahlanweisungen: das if
Aussage und die switch
Aussage.
Das if
Aussage ist in der Form:
wenn (<Ausdruck>) <Erklärung1> anders <Erklärung2>
In dem if
Erklärung, wenn die
In Klammern ist ungleich Null (TRUE), die Kontrolle übergeht zu
. Wenn die else
Klausel ist vorhanden und die
ist null (falsch), die Kontrolle wird an weitergehen
. Das anders
Der Teil ist optional und fernwesend ein Falsch
wird einfach dazu führen, über das zu springen
. Ein else
stimmt immer mit den nächsten vorherigen Ungewachen überein if
; Zahnspangen können verwendet werden, um dies bei Bedarf oder aus Gründen der Klarheit zu überschreiben.
Das switch
Die Aussage führt dazu Ausdruck, was haben muss integraler Typ. Der von einem Schalter gesteuerte Substatement ist typischerweise zusammengesetzt. Jede Aussage innerhalb des Substatatements kann mit einem oder mehreren gekennzeichnet werden case
Etiketten, die aus dem Schlüsselwort bestehen case
gefolgt von einem ständigen Ausdruck und dann einem Dickdarm (:). Die Syntax ist wie folgt:
Schalter (<Ausdruck>) { Fall <Label1> : <Aussagen 1> Fall <Label2> : <Aussagen 2> Unterbrechung; Ursprünglich : <Aussagen 3> }
Keine zwei der mit demselben Schalter verbundenen Fallkonstanten können den gleichen Wert haben. Es kann höchstens eins geben default
Etikett mit einem Schalter verbunden. Wenn keiner der Fallbezeichnungen dem Ausdruck in den folgenden Klammern entspricht switch
, die Kontrolle geht an die default
Etikett oder, wenn es keine gibt default
Etikett, die Ausführung wird direkt über das gesamte Konstrukt hinausgeht.
Schalter können verschachtelt sein; a case
oder default
Etikett ist mit dem innersten verbunden switch
das enthält es. Switch -Anweisungen können "durchfallen", dh wenn ein Fallabschnitt seine Ausführung abgeschlossen hat, werden Anweisungen weiter nach unten ausgeführt, bis a break;
Aussage wird angetroffen. Der Herbst ist unter bestimmten Umständen nützlich, wird aber normalerweise nicht erwünscht. Im vorhergehenden Beispiel, wenn
ist erreicht, die Aussagen
werden ausgeführt und nichts mehr innerhalb der Klammern. jedoch, wenn
ist erreicht, beide
und
werden ausgeführt, da es keine gibt break
Um die beiden Fallanweisungen zu trennen.
Es ist möglich, wenn auch ungewöhnlich, die einzulegen switch
Beschriftungen in die Unterblocks anderer Kontrollstrukturen. Beispiele hierfür sind einzuziehen Duffs Gerät und Simon TathamImplementierung von Coroutinen in Kitt.[9]
Iterationsaussagen
C hat drei Formen von Wiederholung Aussage:
tun <Aussage> während ( <Ausdruck> ) ; während ( <Ausdruck> ) <Aussage> zum ( <Ausdruck> ; <Ausdruck> ; <Ausdruck> ) <Aussage>
In dem while
und do
Aussagen, die Untervoraussetzung wird wiederholt ausgeführt, solange der Wert des expression
bleibt ungleich Null (gleichwertig zu wahr). Mit while
, der Test, einschließlich aller Nebenwirkungen von
, tritt vor jeder Iteration auf (Ausführung von
); mit do
Der Test tritt nach jeder Iteration auf. Also a do
Aussage führt immer mindestens einmal ihre Unterbefragung aus, während while
kann die Unterbeamte überhaupt nicht ausführen.
Die Aussage:
zum (E1; E2; E3) s;
ist äquivalent zu:
E1; während (E2) { s; Fortsetzung: E3; }
außer dem Verhalten von a continue;
Aussage (welche in der for
Loop springt zu e3
Anstatt von e2
). Wenn e2
ist leer, es müsste durch a ersetzt werden 1
.
Jeder der drei Ausdrücke in der for
Schleife kann weggelassen werden. Ein fehlender zweiter Ausdruck macht das while
Test immer ungleich Null und erzeugt eine potenziell unendliche Schleife.
Seit C99Der erste Ausdruck kann in Form einer Erklärung angehen, die normalerweise einen Initialisierer enthält, wie z. B.:
zum (int i = 0; i < Grenze; ++i) { // ... }
Der Zielfernrohr der Erklärung ist auf das Ausmaß der for
Schleife.
Sprunganweisungen
Sprunganweisungen übertragen die Kontrolle bedingungslos. Es gibt vier Arten von Sprunganweisungen in C: goto
, continue
, break
, und return
.
Das goto
Aussage sieht so aus:
gehe zu <Kennung> ;
Das Kennung muss ein sein Etikett (gefolgt von einem Dickdarm) in der aktuellen Funktion. Kontrollübertragung in die markierte Anweisung.
A continue
Aussage kann nur innerhalb eines erscheinen Iterationserklärung und bewirkt, dass die Kontrolle an den Schleifenabschnitt der innersten Iterationsaussage übergeht. Das heißt, innerhalb jeder der Aussagen
während (Ausdruck) { / * ... */ Fortsetzung: ; } tun { / * ... */ Fortsetzung: ; } während (Ausdruck); zum (Expr1; expr2; Expr3) { / * ... */ Fortsetzung: ; }
a continue
Nicht in einer verschachtelten Iterationserklärung enthalten ist die gleiche wie goto cont
.
Das break
Anweisung wird verwendet, um a zu beenden for
Schleife, while
Schleife, do
Schleife, oder switch
Aussage. Die Kontrolle übergeht nach der beendeten Erklärung an die Erklärung.
Eine Funktion kehrt durch die zu ihrem Anrufer zurück return
Aussage. Wann return
Nach einem Ausdruck wird der Wert als Wert der Funktion an den Anrufer zurückgegeben. Die Begegnung auf das Ende der Funktion entspricht a return
ohne Ausdruck. In diesem Fall ist das Ergebnis undefiniert, wenn die Funktion als Rückgabe eines Wertes deklariert wird und der Anrufer versucht, den zurückgegebenen Wert zu verwenden.
Speichern der Adresse eines Etiketts
GCC erweitert die C -Sprache mit einem Unary &&
Bediener, der die Adresse eines Etiketts zurückgibt. Diese Adresse kann in a gespeichert werden void*
variabler Typ und kann später in a verwendet werden goto
Anweisung. Zum Beispiel die folgenden Drucke "hi "
in einer unendlichen Schleife:
Leere *ptr = &&J1; J1: printf("hallo "); gehe zu *ptr;
Diese Funktion kann verwendet werden, um a zu implementieren Sprungtisch.
Funktionen
Syntax
Eine C -Funktionsdefinition besteht aus a Rückgabetyp (void
Wenn kein Wert zurückgegeben wird), ein eindeutiger Name, eine Liste von Parametern in Klammern und verschiedene Aussagen:
<Rückkehr-Typ> Funktionsname( <Parameter-aufführen> ) { <Aussagen> Rückkehr <Ausdruck von Typ Rückkehr-Typ>; }
Eine Funktion mit nichtvoid
Der Rückgabetyp sollte mindestens einen enthalten return
Aussage. Die Parameter werden von der gegeben
, Eine von Kommas getrennte Liste von Parameterdeklarationen, wobei jedes Element in der Liste ein Datentyp ist, gefolgt von einer Kennung:
.
Wenn es keine Parameter gibt, die
kann leer bleiben oder optional mit dem einzelnen Wort angegeben werden void
.
Es ist möglich, eine Funktion zu definieren, die eine variable Anzahl von Parametern durch Bereitstellung des ...
Schlüsselwort als letzter Parameter anstelle eines Datentyps und einer Variablenkennung. Eine häufig verwendete Funktion, die dies tut, ist die Standardbibliotheksfunktion printf
, was die Erklärung hat:
int printf (Const verkohlen*, ...);
Die Manipulation dieser Parameter kann durch die Verwendung der Routinen im Standardbibliotheksheader durchgeführt werden
.
Funktionszeiger
Ein Zeiger auf eine Funktion kann wie folgt deklariert werden:
<Rückkehr-Typ> (*<<Funktion-Name>) (<Parameter-aufführen>);
Das folgende Programm zeigt die Verwendung von a Funktionszeiger Zur Auswahl zwischen Addition und Subtraktion:
#enthalten int (*Betrieb) (int x, int y); int hinzufügen(int x, int y) { Rückkehr x + y; } int subtrahieren(int x, int y) { Rückkehr x - y; } int hauptsächlich(int argc, verkohlen* Args[]) { int Foo = 1, Bar = 1; Betrieb = hinzufügen; printf(" %d + %d = %d\n", Foo, Bar, Betrieb(Foo, Bar)); Betrieb = subtrahieren; printf(" %d - %d = %d\n", Foo, Bar, Betrieb(Foo, Bar)); Rückkehr 0; }
Globale Struktur
Nach der Vorverarbeitung auf höchstem Niveau a C Programm besteht aus einer Abfolge von Deklarationen im Dateiumfang. Diese können in mehrere separate Quelldateien unterteilt werden, die separat kompiliert werden können. Die resultierenden Objektmodule sind dann verknüpft Zusammen mit der implementierenden Laufzeit-Support-Module zur Erzeugung eines ausführbaren Bildes.
Die Erklärungen führen ein Funktionen, Variablen und Typen. C -Funktionen sind mit den Unterprogrammen von vergleichbar Forran oder die Verfahren von Pascal.
A Definition ist eine besondere Art von Deklaration. Eine Variablendefinition legt den Speicher beiseite und initialisiert sie möglicherweise, eine Funktionsdefinition liefert ihren Körper.
Eine Implementierung von C, die alle Standardbibliotheksfunktionen bereitstellt, wird als a genannt Hosted Implementierung. Programme für gehostete Implementierungen sind erforderlich, um eine spezielle Funktion namens zu definieren main
, was die erste Funktion ist, die genannt wird, wenn ein Programm mit der Ausführung beginnt.
Hosted Implementierungen starten die Programmausführung, indem Sie die aufrufen main
Funktion, die nach einem dieser Prototypen definiert werden muss:
int hauptsächlich() {...} int hauptsächlich(Leere) {...} int hauptsächlich(int argc, verkohlen *argv[]) {...} int hauptsächlich(int argc, verkohlen **argv) {...}
Die ersten beiden Definitionen sind äquivalent (und beide sind mit C ++ kompatibel). Es liegt wahrscheinlich an individuelle Präferenzen, die man verwendet wird (der aktuelle C -Standard enthält zwei Beispiele von main()
und zwei von main(void)
, aber der Entwurf C ++ Standard verwendet main()
). Der Rückgabewert von main
(Welches sollte sein int
) dient als Kündigungsstatus kehrte in die Wirtsumgebung zurück.
Der C -Standard definiert Rückgabewerte 0
und EXIT_SUCCESS
als Hinweis auf Erfolg und EXIT_FAILURE
als Hinweis auf Fehler. (EXIT_SUCCESS
und EXIT_FAILURE
sind in definiert in
). Andere Rückgabewerte haben implementierende Bedeutungen; Zum Beispiel unter Linux ein Programm, das von a getötet wurde Signal Ergibt einen Rückgabecode des numerischen Wertes des Signals plus 128.
Ein minimales korrektes C -Programm besteht aus einem leeren main
Routine, keine Argumente annehmen und nichts tun:
int hauptsächlich(Leere) {}
Weil Nein Rückkehr
Aussage ist vorhanden, hauptsächlich
Gibt 0 beim Ausgang zurück.[3] (Dies ist eine Spezialfallfunktion, die in eingeführt wird C99 das gilt nur für hauptsächlich
.))
Das main
Die Funktion ruft normalerweise andere Funktionen auf, um ihre Aufgabe auszuführen.
Einige Implementierungen werden nicht gehostet, normalerweise weil sie nicht mit einem verwendet werden sollen Betriebssystem. Solche Implementierungen werden genannt freistehend im C -Standard. Eine freistehende Implementierung ist kostenlos, wie sie mit dem Programm Startup umgehen. Insbesondere muss kein Programm erforderlich sein, um a zu definieren main
Funktion.
Funktionen können vom Programmierer verfasst oder von vorhandenen Bibliotheken bereitgestellt werden. Schnittstellen für letztere werden normalerweise durch Einbeziehung von Header -Dateien deklariert - mit dem #include
Vorverarbeitungsrichtlinie- und die Bibliotheksobjekte sind mit dem endgültigen ausführbaren Bild verbunden. Bestimmte Bibliotheksfunktionen, wie z. printf
, werden durch den C -Standard definiert; Diese werden als die bezeichnet Standardbibliothek Funktionen.
Eine Funktion kann einen Wert an den Anrufer zurückgeben (normalerweise eine andere C -Funktion oder die Hosting -Umgebung für die Funktion main
). Das printf
Die oben erwähnte Funktion gibt zurück, wie viele Zeichen gedruckt wurden, aber dieser Wert wird oft ignoriert.
Argument passieren
In C werden Argumente an Funktionen übergeben nach Wert während andere Sprachen Variablen übergeben können durch Bezugnahme. Dies bedeutet, dass die Empfangsfunktion Kopien der Werte erhält und keine direkte Möglichkeit hat, die ursprünglichen Variablen zu ändern. Damit eine Funktion eine von einer andere Funktion übergebene Variable verändert, muss der Anrufer seine übergeben die Anschrift (a Zeiger dazu), was dann in der Empfangsfunktion derenferenziert werden kann. Sehen Zeiger für mehr Informationen.
Leere Incint(int *y) { (*y)++; // Erhöhen Sie den Wert von 'x' in 'Main' unten um eins } int hauptsächlich(Leere) { int x = 0; Incint(&x); // Übergeben Sie einen Verweis auf das Var 'x' Rückkehr 0; }
Die Funktion Scanf funktioniert genauso:
int x; Scanf("%d", &x);
Um einen bearbeitbaren Zeiger auf eine Funktion zu übergeben (z. das Zeiger: seine Adresse.
#enthalten #enthalten Leere Allocate_array(int ** Const a_p, Const int A) { /* Zuordnen Sie eine Reihe von INTs aus Zuweisen an *a_p verändert das 'a' in main () */ *a_p = Malloc(Größe von(int) * A); } int hauptsächlich(Leere) { int * a; / * Erstellen Sie einen Zeiger auf eine oder mehrere INTs, dies ist das Array */ / * Übergeben Sie die Adresse von 'a' */ Allocate_array(&a, 42); / * 'a' ist jetzt eine Reihe von Länge 42 und kann hier manipuliert und befreit werden */ frei(a); Rückkehr 0; }
Der Parameter int **a_p
ist ein Zeiger auf einen Zeiger auf eine int
, die die Adresse des Zeigers ist p
definiert in der hauptsächlich Funktion in diesem Fall.
Array -Parameter
Funktionsparameter des Array-Typs können auf den ersten Blick eine Ausnahme von Cs Pass-by-Wert-Regel sein. Das folgende Programm druckt 2, nicht 1:
#enthalten Leere setArray(int Array[],, int Index, int Wert) { Array[Index] = Wert; } int hauptsächlich(Leere) { int a[1] = {1}; setArray(a, 0, 2); printf ("a [0] =%d\n", a[0]); Rückkehr 0; }
Es gibt jedoch einen anderen Grund für dieses Verhalten. Tatsächlich wird ein mit einem Array -Typ deklarierter Funktionsparameter wie einer als Zeiger behandelt. Das heißt, die vorhergehende Erklärung von setArray
entspricht Folgendes:
Leere setArray(int *Array, int Index, int Wert)
Gleichzeitig verursachen c C -Regeln für die Verwendung von Arrays in Ausdrücken den Wert von a
im Anruf an setArray
zu einem Zeiger auf das erste Element des Arrays konvertiert werden a
. In der Tat ist dies also immer noch ein Beispiel für Pass-by-Wert, mit der Einschränkung, dass es die Adresse des ersten Elements des Arrays ist, das von Wert übergeben wird, nicht der Inhalt des Arrays.
Sonstig
Reservierte Schlüsselwörter
Die folgenden Wörter sind reserviertund darf nicht als Bezeichner verwendet werden:
|
|
|
|
Implementierungen können andere Schlüsselwörter reservieren, wie z. asm
, obwohl Implementierungen in der Regel nicht standardmäßige Schlüsselwörter bereitstellen, die mit einem oder zwei Unterstrichen beginnen.
Fallempfindlichkeit
C -Identifikatoren sind Fallempfindlichkeit (z. B.,, foo
, FOO
, und Foo
sind die Namen verschiedener Objekte). Einige Linker können externe Kennungen einem einzigen Fall zuordnen, obwohl dies in den meisten modernen Linken ungewöhnlich ist.
Kommentare
Text beginnend mit dem Zeichen /*
wird als a behandelt Kommentar und ignoriert. Der Kommentar endet am nächsten */
; Es kann innerhalb der Ausdrücke auftreten und mehrere Zeilen umfassen. Ein versehentliches Auslassen des Kommentarterminators ist insofern problematisch, als der ordnungsgemäß konstruierte Kommentar -Terminator des nächsten Kommentars zur Beendigung des ersten Kommentars verwendet wird, und der gesamte Code zwischen den Kommentaren wird als Kommentar angesehen. C-Art-Kommentare nisten nicht; Das heißt, versehentlich einen Kommentar in einen Kommentar zu bringen, hat unbeabsichtigte Ergebnisse:
/* Diese Linie wird ignoriert. /* Hier kann eine Compiler -Warnung produziert werden. Diese Zeilen werden auch ignoriert. Der oberste Kommentar, der oben geöffnet wurde, startete keinen neuen Kommentar. Und der Kommentar schließt unten den unten stehenden Kommentar in Zeile 1. */ Dies Linie und das Linie unter es Wille nicht sein ignoriert. Beide Wille wahrscheinlich produzieren kompilieren Fehler. */
C ++ Style Line Kommentare beginnen mit //
und erstreckt sich bis zum Ende der Linie. Dieser Kommentarstil entstand von BCPL und wurde eine gültige C -Syntax in C99; Es ist weder im ursprünglichen K & R C noch in verfügbar Ansi c:
// Diese Zeile wird vom Compiler ignoriert /* diese Zeilen wird ignoriert vom Compiler */ x = *p/*q; / * Dieser Kommentar beginnt nach dem 'P' */
Kommandozeilenargumente
Das Parameter auf a Befehlszeile werden an ein C -Programm mit zwei vordefinierten Variablen übergeben - die Anzahl der Befehlszeilenargumente in argc
und der Individuum Argumente wie Charakterzeichenfolgen im Zeigerarray argv
. Also der Befehl:
myFilt p1 p2 p3
führt in so etwas wie:
m | y | F | i | l | t | \0 | p | 1 | \0 | p | 2 | \0 | p | 3 | \0 |
argv [0] | Argv [1] | Argv [2] | Argv [3] |
Während einzelne Saiten Arrays von zusammenhängenden Zeichen sind, gibt es keine Garantie dafür, dass die Saiten als zusammenhängende Gruppe gespeichert werden.
Der Name des Programms, argv[0]
, kann nützlich sein, wenn diagnostische Nachrichten drucken oder eine Binärdatei mehrere Zwecke dienen. Auf die einzelnen Werte der Parameter können zugegriffen werden argv[1]
, argv[2]
, und argv[3]
, wie im folgenden Programm gezeigt:
#enthalten int hauptsächlich(int argc, verkohlen *argv[]) { printf("Argc\t= %d\n", argc); zum (int i = 0; i < argc; i++) printf("argv [%i]\t= %s\n", i, argv[i]); }
Bewertungsauftrag
In jedem einigermaßen komplexen Ausdruck entsteht die Auswahl der Reihenfolge, in der die Teile des Ausdrucks bewertet werden können: (1+1)+(3+3)
kann in der Reihenfolge bewertet werden (1+1)+(3+3)
, (2)+(3+3)
, (2)+(6)
, (8)
oder in der Reihenfolge (1+1)+(3+3)
, (1+1)+(6)
, (2)+(6)
, (8)
. Formal kann ein konformer C -Compiler die Ausdrücke in bewerten irgendein Ordnung zwischen Sequenzpunkte (Dadurch kann der Compiler eine gewisse Optimierung durchführen). Sequenzpunkte werden definiert durch:
- Aussage endet in Semikolons.
- Das Sequenzierungsoperator: ein Komma. Kommas, dass die Ausgrenzungsfunktionsargumente jedoch keine Sequenzpunkte sind.
- Das Kurzschlussbetreiber: logisch und (
&&
, was gelesen werden kann und dann) und logisch oder (||
, was gelesen werden kann oder aber). - Das ternärer Operator (
?:
): Dieser Operator bewertet zuerst seine erste Unterexpression und dann seine zweite oder dritte (nie beide) basierend auf dem Wert des ersten. - Eintritt zu und Ausfahrt von a Funktionsaufruf (aber nicht zwischen Bewertungen der Argumente).
Ausdrücke vor einem Sequenzpunkt werden immer vor denen nach einem Sequenzpunkt bewertet. Bei der Bewertung der Kurzschlusskreis kann der zweite Ausdruck abhängig vom Ergebnis des ersten Ausdrucks nicht bewertet werden. Zum Beispiel im Ausdruck (a() || b())
Wenn das erste Argument an ungleich Null (wahr) bewertet wird, kann das Ergebnis des gesamten Ausdrucks nichts anderes als wahr sein, also b()
wird nicht bewertet. Ebenso im Ausdruck (a() && b())
Wenn das erste Argument auf Null bewertet wird (Falsch), kann das Ergebnis des gesamten Ausdrucks nichts anderes als false sein, also b()
wird nicht bewertet.
Die Argumente für einen Funktionsaufruf können in beliebiger Reihenfolge bewertet werden, solange sie alle bis zu dem Zeitpunkt der Eingabe der Funktion bewertet werden. Der folgende Ausdruck hat zum Beispiel ein undefiniertes Verhalten:
printf(" %s %s\n", argv[i = 0], argv[++i]);
Undefiniertes Verhalten
Ein Aspekt des C -Standards (nicht einzigartig in C) ist, dass das Verhalten bestimmter Code als "undefiniert" bezeichnet wird. In der Praxis bedeutet dies, dass das aus diesem Code produzierte Programm alles tun kann, von der Arbeit als Programmierer bis hin zum Absturz jedes Mal, wenn es ausgeführt wird.
Zum Beispiel erzeugt der folgende Code ein undefiniertes Verhalten, da die Variable b wird mehr als einmal ohne intervenierende Sequenzpunkt geändert:
#enthalten int hauptsächlich(Leere) { int b = 1; int a = b++ + b++; printf("%d\n", a); }
Weil es keinen Sequenzpunkt zwischen den Modifikationen von gibt b in "b++ + b++ "Es ist möglich, die Bewertungsschritte in mehr als einer Reihenfolge auszuführen, was zu einer mehrdeutigen Aussage führt. Dies kann behoben werden, indem der Code neu geschrieben wird, um einen Sequenzpunkt einzufügen, um ein eindeutiges Verhalten durchzusetzen, z. B.:
a = b++; a += b++;
Siehe auch
- Blocks (C language extension)
- C Programmiersprache
- C variable Typen und Deklarationen
- Operatoren in C und C ++
- C Standardbibliothek
- Liste der Programmiersprachen der C-Familie (C-beeinflusste Sprachen)
Verweise
- ^ a b Das
long long
Modifikator wurde in der eingeführt C99 Standard. - ^ Die Bedeutung von Auto ist eher ein Typ -Spezifizierer als ein Speicherklassenspezifizierer in C ++ 0x
- ^ a b c Klemens, Ben (2012). 21. Jahrhundert c. O'Reilly Media. ISBN 978-1449327149.
- ^ Balagurusamy, E. Programmierung in ANSI C. Tata McGraw Hill. p. 366.
- ^ "Der C-Präprozessor: Implementierungsdefinierte Verhalten". gcc.gnu.org.
- ^ "String- und Zeichenliterale (C ++)". Visual C ++ 19 Dokumentation. Abgerufen 20. November 2019.
- ^ sehen UTF-8 Erster Abschnitt für Referenzen
- ^ Kernighan & Richie
- ^ Tatham, Simon (2000). "Coroutinen in C". Abgerufen 2017-04-30.
- Allgemein
- Kernighan, Brian W.; Ritchie, Dennis M. (1988). Die C -Programmiersprache (2. Aufl.). Upper Saddle River, New Jersey: Prentice Hall PTR. ISBN 0-13-110370-9.
- American National Standard für Informationssysteme - Programmiersprache - C - ANSI X3.159-1989