Was sind die nützlichsten neuen Funktionen in C99? [geschlossen]

78

C99 gibt es seit über 10 Jahren, aber die Unterstützung dafür kommt nur langsam, so dass die meisten Entwickler bei C89 geblieben sind. Selbst heute bin ich manchmal leicht überrascht, wenn ich auf C99-Funktionen im C-Code stoße.

Da die meisten großen Compiler C99 unterstützen (MSVC ist eine bemerkenswerte Ausnahme, und einige eingebettete Compiler bleiben ebenfalls zurück), sollten Entwickler, die mit C arbeiten, wahrscheinlich wissen, welche C99-Funktionen ihnen zur Verfügung stehen. Einige der Funktionen sind nur allgemeine Funktionen, die zuvor noch nie standardisiert wurden ( snprintfz. B.) oder aus C ++ bekannt sind (flexible Platzierung von Variablendeklarationen oder einzeilige //Kommentare). Einige der neuen Funktionen wurden jedoch erstmals in C99 eingeführt und sind es auch vielen Programmierern unbekannt.

Was sind die nützlichsten neuen Funktionen in C99?

Als Referenz der C99-Standard (als Entwurf gekennzeichnet, aber meines Wissens identisch mit dem aktualisierten Standard), die Liste der neuen Funktionen und der Implementierungsstatus des GCC C99 .

Bitte eine Funktion pro Antwort; Fühlen Sie sich frei, mehrere Antworten zu hinterlassen. Es wird empfohlen, kurze Codebeispiele zu verwenden, die neue Funktionen demonstrieren.

Brian Campbell
quelle
2
Es sollte ein ähnliches Wiki für Funktionen geben, die die Leute in C99 hassen !
Alok Singhal
Nun, es gab eine Frage zu schädlichen oder nicht unterstützten C99-Funktionen stackoverflow.com/questions/1898890/…
Brian Campbell
Vielen Dank. Sie sollten den Linktext ändern, um anzuzeigen, dass es sich um einen Entwurf handelt, nicht den tatsächlichen Standard, und einen Link zu n1256 erstellen, während Sie gerade dabei sind :-). BTW, bei der Suche gcc.gnu.org/c99status.html , würde ich nicht sagen , die meisten von C99 wird von gcc unterstützt. Und da gcc einer der am häufigsten verwendeten C-Compiler ist, ...
Alok Singhal
2
Beachten Sie, dass C99 im Bereich der eingebetteten Prozessoren möglicherweise immer noch nicht gut unterstützt wird.
Craig McQueen
1
@Alok Ich würde diese Unterstützungsstufe die meisten Funktionen nennen; Ich nehme an, es hängt davon ab, wie Sie es definieren, aber ich denke, dass die meisten wichtigen Funktionen, die Benutzer verwenden möchten, unterstützt werden, abgesehen von einigen Bibliotheksproblemen. @Craig Fair genug, fügte einen Haftungsausschluss über eingebettete Compiler hinzu.
Brian Campbell

Antworten:

77

Ich bin es so gewohnt zu tippen

for (int i = 0; i < n; ++i) { ... }

In C ++ ist es ein Schmerz, einen Nicht-C99-Compiler zu verwenden, wo ich gezwungen bin zu sagen

int i;
for (i = 0; i < n; ++i ) { ... }
Jon Reid
quelle
44
Außerdem
schränkt
Das wäre auch meine Wahl.
figurassa
2
@Oliver <Sarkasmus> aber dann die Anweisungen sub esp, 4und add esp, 4werden entfernt! </ Sarkasmus>
Cole Johnson
72

stdint.h, was definiert int8_t, uint8_tusw. Sie müssen keine nicht tragbaren Annahmen mehr darüber treffen, wie breit Ihre ganzen Zahlen sind.

uint32_t truth = 0xDECAFBAD;
Brian Campbell
quelle
19
Beste Hex-Phrase seit DE: AD: BE: EF: CA: FE.
Kevin L.
Was soll Decafbad bedeuten?
Pacerier
5
@Pacerier Es ist nur eine beliebige hexadezimale Konstante, die zur Veranschaulichung des Beispiels verwendet wird. Aber für den Humorwert bedeutet es "decaf bad", was bedeutet, dass entkoffeinierter Kaffee der Realität unterlegen ist.
Brian Campbell
5
ok, ich kann mich nicht auf ihren Humor beziehen ...
Pacerier
66

Ich denke, dass die neuen Initialisierungsmechanismen äußerst wichtig sind.

struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } };

OK - kein überzeugendes Beispiel, aber die Notation ist korrekt. Sie können bestimmte Elemente eines Arrays und bestimmte Elemente einer Struktur initialisieren.

Vielleicht wäre dies ein besseres Beispiel - obwohl ich zugeben würde, dass es nicht sehr überzeugend ist:

enum { Iron = 26, Aluminium = 13, Beryllium = 4, ... };

const char *element_names[] =
{
    [Iron]      = "Iron",
    [Aluminium] = "Aluminium",
    [Beryllium] = "Beryllium",
    ...
};
Jonathan Leffler
quelle
6
Das ist eine überzeugende Demonstration. Es gibt eine große Anzahl von Aufzählungstabellen mit entsprechenden Zeichenfolgentabellen.
u0b34a0f6ae
5
@ColeJohnson: Wenn Sie sich das zweite Beispiel genau ansehen, werden Sie feststellen, dass die Initialisierer nicht in der richtigen Reihenfolge aufgeführt sind - aber ordnungsgemäß funktionieren. Das geht nicht einfach mit Definitionen. Das erste Beispiel initialisiert nur den Index 4 des Arrays. Das geht auch nicht einfach mit Definitionen.
Jonathan Leffler
2
Es sollte auch darauf hingewiesen werden , dass mit dem gleichen Index mehr mit als einmal die erste Nutzung mit dem zweiten außer Kraft setzen - siehe meine Frage hier, zum Beispiel: stackoverflow.com/questions/16742467/...
johnny
51

Arrays mit variabler Länge:

int x;
scanf("%d", &x);
int a[x];
for (int i = 0; i < x; ++i)
    a[i] = i * i;
for (int i = 0; i < x; ++i)
    printf("%d\n", a[i]);
Mehrdad Afshari
quelle
3
Sie finden VLA-Arrays wirklich so großartig? C11 macht sie optional.
Z Boson
3
Vergessen Sie nur nicht, eine Eingabesanierung anzuwenden, um einen Stapelüberlauf (oder eine if (x < 0) x = 0; else if (x > 1024) x = 1024;
Stapelbeschädigung
51

Unterstützung für einzeilige Kommentare beginnend mit //.

Gameover
quelle
7
+1 ALLE mir bekannten Compiler unterstützen dies bereits. Es ist an der Zeit, dass es im Standard erwähnt wird.
Slebetman
41

In der Lage sein, Variablen an anderen Stellen als am Anfang eines Blocks zu deklarieren.

mikecsh
quelle
2
Darauf bin ich nicht so scharf. Meiner Meinung nach sollten Variablen nicht nur bei Bedarf in den Geltungsbereich gebracht, sondern bei Bedarf auch aus dem Geltungsbereich entfernt werden. Variablen in der Mitte des Blocks hängen fast immer länger im Umfang als sie sollten.
Supercat
5
@supercat Sie lieber int a; int b; a = f(); b = g();zu int a = f(); int b = g();? Das Deklarieren einer Variablen in der Nähe des Initialisierungsortes ist sehr wichtig, um Fehler zu reduzieren.
Ryan Haining
@RyanHaining: Alternativ können Sie einen verschachtelten Bereichsblock erstellen (ich wünschte nur, es gäbe eine Standardsyntax, die besagt, dass "dieser Block nur zum Scoping dient"; man kann leicht ein Nullmakro für diesen Zweck verwenden, aber das scheint ein bisschen hässlich zu sein.
Supercat
@supercat Es gibt eine Standardsyntax dafür: /* this block is just for scoping */ { } /* scope */:)
Cacahuete Frito
@CacahueteFrito: Ich denke, es if(1) /* Scoping block */ { }ist ein bisschen besser, aber ein größeres Problem ist, dass Scoping und Kontrolle orthogonale Konzepte sind. Es gibt Zeiten, in denen es sinnvoll ist, Dinge innerhalb einer Schleife zu erfassen, aber es ist häufiger nützlich, Dinge nur um die Schleife herum zu haben, und es gibt auch viele Male, in denen Code Objekte mit Werten erstellt, die für die Erstellung von erforderlich sind float dx=x2-x1, dy=y2-y1; float distance = sqrt(dx*dx+dy*dy);
längerlebige
36

Variadische Makros. Erleichtert das Generieren von Boilerplate-Code mit unbegrenzter Anzahl von Argumenten.

kennytm
quelle
34

snprintf() - Im Ernst, es ist viel wert, sichere formatierte Zeichenfolgen erstellen zu können.

David Thornley
quelle
1
Sehr richtig. Ich würde diese Antwort selbst hinzufügen, wenn es sonst niemand tat.
Brian Campbell
29

Zusammengesetzte Literale. Das Setzen von Strukturen von Mitglied zu Mitglied ist also '89;)

Sie können sie auch verwenden, um Zeiger auf Objekte mit automatischer Speicherdauer abzurufen, ohne unnötige Variablen zu deklarieren, z

foo(&(int){ 4 });

insteand von

int tmp = 4;
foo(&tmp);
Christoph
quelle
Es sollte inturn Speicher auf Stapel für 4 zuweisen, oder?
AlphaGoku
29

Flexible Array-Mitglieder.

6.7.2.1 Struktur- und Gewerkschaftsspezifizierer

Als Sonderfall kann das letzte Element einer Struktur mit mehr als einem benannten Element einen unvollständigen Array-Typ haben. Dies wird als flexibles Array-Mitglied bezeichnet . Mit zwei Ausnahmen wird das flexible Array-Mitglied ignoriert. Erstens muss die Größe der Struktur gleich dem Versatz des letzten Elements einer ansonsten identischen Struktur sein, die das flexible Array-Element durch ein Array nicht spezifizierter Länge ersetzt.) Zweitens, wenn a .(oder->) Der Operator hat einen linken Operanden, der (ein Zeiger auf) eine Struktur mit einem flexiblen Array-Element ist, und der rechte Operand benennt dieses Element. Es verhält sich so, als würde dieses Element durch das längste Array (mit demselben Elementtyp) ersetzt, das dies nicht tun würde die Struktur größer machen als das Objekt, auf das zugegriffen wird; Der Versatz des Arrays muss der des flexiblen Array-Elements bleiben, auch wenn dies von dem des Ersatz-Arrays abweichen würde. Wenn dieses Array keine Elemente enthalten würde, verhält es sich so, als hätte es ein Element, aber das Verhalten ist nicht definiert, wenn versucht wird, auf dieses Element zuzugreifen oder einen Zeiger nach dem Element zu generieren.

Beispiel:

typedef struct {
  int len;
  char buf[];
} buffer;

int bufsize = 100;
buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize]));
Gregory Pakosz
quelle
2
+1 für endlich koscher machen. Es ist in jedem TCP / IP-Socket-Code enthalten, den ich je gesehen habe.
Slebetman
In der Tat würde ich es als weitaus koscher betrachten als den üblichen Trick, buf [1] zu verwenden und 1 von der Malloc-Größe zu subtrahieren. Der Trick mag üblich sein, aber ich würde ihn als undefiniertes Verhalten betrachten (richtig wäre es, buf [MAX_SIZE] zu verwenden und MAX_SIZE von der Malloc-Größe zu subtrahieren), da der vom Compiler generierte Indexcode von der wahrgenommenen Größe von buf [] abhängen kann.
Supercat
25

Der Bool-Typ.

Sie können jetzt so etwas tun:

bool v = 5;

printf("v=%u\n", v);

wird gedruckt

1
Patrick Schlüter
quelle
2
wer daran gedacht hat, ist rein genial
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
Nein, boolin C99 wird der der Variablen zugewiesene Wert immer auf 1 oder 0 gesetzt. Deshalb müssen Sie vorsichtig sein, wenn Sie Code haben, der auf einem C99-Compiler und auf einem älteren Compiler mit "simuliertem" boolTyp ausgeführt wird. Mit !!wird das tragbar. v = !!5;hat die gleiche Semantik, ist aber nicht so lesbar.
Patrick Schlüter
Wird 1 ausgegeben, wenn eine gerade Zahl wie 6 zugewiesen wird?
Phuclv
Ja. Jeder Wert ungleich Null wird durch 1 ersetzt.
Patrick Schlüter
18

Unterstützung für inlineFunktionen.

CodeRain
quelle
In der Praxis ignoriert GCC normalerweise das Inline-Schlüsselwort, wenn es entscheidet, welche Funktionen inline sind, und inline automatisch Dinge basierend auf seinen eigenen Heuristiken, sofern Sie es nicht dazu zwingen, etwas anderes zu tun.
daf
7
daf: inlinehilft trotzdem, da Sie die Funktion in mehr als einer Übersetzungseinheit definieren können. Sie können sie also in eine Header-Datei einfügen, die modulübergreifende Inlining-Möglichkeiten bietet.
Café
@ Dafinline __attribute__((force_inline))
Cole Johnson
18

Zusammengesetzte Literale, bereits erwähnt, aber hier ist mein überzeugendes Beispiel:

struct A *a = malloc(sizeof(*a));
*a = (struct A){0};  /* full zero-initialization   */
/* or */
*a = (struct A){.bufsiz=1024, .fd=2};   /* rest are zero-initialized.  */

Es ist eine klare Möglichkeit, Daten zu initialisieren, selbst wenn sie sich auf dem Heap befinden. Es gibt keine Möglichkeit zu vergessen, etwas auf Null zu initialisieren.

u0b34a0f6ae
quelle
17

Das restrictSchlüsselwort. Vor allem, wenn Sie Zahlen knacken ...

Alexandre C.
quelle
15

Unterstützung für Unicode-Escape-Sequenzen:

printf("It's all \u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC to me.\n");

Oder sogar wörtliche Unicode-Zeichen:

printf("日本語\n");

(Hinweis: Abhängig von Ihrem Gebietsschema funktioniert dies möglicherweise nicht. Die tragbare Unterstützung für verschiedene Codierungen erfordert mehr Arbeit.)

Brian Campbell
quelle
12

Hexadezimale Gleitkommakonstanten ( 0x1.8p0f) und Konvertierungsspezifizierer ( %a, %A). Wenn Sie häufig mit numerischen Details auf niedriger Ebene arbeiten, ist dies eine enorme Verbesserung gegenüber Dezimalliteralen und Konvertierungen.

Sie ersparen Ihnen die Sorge um Rundungen bei der Angabe von Konstanten für einen Algorithmus und sind äußerst nützlich für das Debuggen von Gleitkomma-Code auf niedriger Ebene.

Stephen Canon
quelle
3
Ja, ich habe diese neulich verwendet, um jemandem zu erklären, wie Gleitkommazahlen in einer anderen Frage zum Stapelüberlauf funktionieren.
Brian Campbell
9

Persönlich mag ich die Anerkennung von IEC 60559: 1989 (Binäre Gleitkomma-Arithmetik für Mikroprozessorsysteme) und eine viel bessere Gleitkomma-Unterstützung.

In ähnlicher Weise ist es großartig, den Gleitkomma-Rundungsmodus einzustellen und abzufragen, nach Nan / Infinity / subnormalen Zahlen usw. zu suchen.

Alok Singhal
quelle
Nun, MS macht das nicht gerne
Cole Johnson
C ist für das Konzept der Rundungsmodi nicht wirklich gut geeignet, da sie bedeuten, dass Gleitkomma-Mathematik als Nebenwirkungen behandelt werden muss. Es ist nützlich, etwas Besseres als die Gleitkommasemantik "Hoffnung auf das Beste" zu haben, aber ich weiß nicht, wie viele Implementierungen wirklich alle Anforderungen von Anhang F
erfüllen