Nur neugierig, was passiert eigentlich, wenn ich ein Array mit der Länge Null int array[0];
im Code definiere? GCC beschwert sich überhaupt nicht.
Beispielprogramm
#include <stdio.h>
int main() {
int arr[0];
return 0;
}
Klärung
Ich versuche tatsächlich herauszufinden, ob Arrays mit der Länge Null, die auf diese Weise initialisiert wurden, optimiert sind oder nicht, anstatt wie in Darhazers Kommentaren auf die variable Länge hingewiesen zu werden.
Dies liegt daran, dass ich Code in die Wildnis freigeben muss, also versuche ich herauszufinden, ob ich Fälle behandeln muss, in denen der SIZE
definiert ist 0
, was in einem Code mit einem statisch definierten Code der Fall istint array[SIZE];
Ich war tatsächlich überrascht, dass sich GCC nicht beschwert, was zu meiner Frage führte. Aufgrund der Antworten, die ich erhalten habe, glaube ich, dass das Fehlen einer Warnung hauptsächlich auf die Unterstützung von altem Code zurückzuführen ist, der nicht mit der neuen [] -Syntax aktualisiert wurde.
Da ich mich hauptsächlich über den Fehler gewundert habe, markiere ich Lundins Antwort als richtig (Nawaz war die erste, aber nicht so vollständig) - die anderen wiesen darauf hin, dass die tatsächliche Verwendung für schwanzgepolsterte Strukturen zwar relevant ist, aber nicht. genau das, wonach ich gesucht habe.
[]
in Python oder sogar""
in C? Manchmal haben Sie eine Funktion oder ein Makro, für das ein Array erforderlich ist, aber Sie müssen keine Daten einfügen.Antworten:
Ein Array kann keine Größe von Null haben.
ISO 9899: 2011 6.7.6.2:
Der obige Text gilt sowohl für ein einfaches Array (Absatz 1). Bei einem VLA (Array mit variabler Länge) ist das Verhalten undefiniert, wenn der Wert des Ausdrucks kleiner oder gleich Null ist (Absatz 5). Dies ist normativer Text im C-Standard. Ein Compiler darf es nicht anders implementieren.
gcc -std=c99 -pedantic
gibt eine Warnung für den Nicht-VLA-Fall aus.quelle
#error
Anweisung gestoßen .#error
Präprozessor-Direktive stößt .Gemäß dem Standard ist es nicht erlaubt.
In C-Compilern ist es jedoch derzeit üblich, diese Deklarationen als FAM- Deklaration (Flexible Array Member ) zu behandeln :
Die Standardsyntax eines FAM lautet:
Die Idee ist, dass Sie es dann so zuweisen würden:
Sie können es auch statisch verwenden (gcc-Erweiterung):
Dies wird auch als schwanzgepolsterte Strukturen (dieser Begriff stammt aus der Zeit vor der Veröffentlichung des C99-Standards) oder als Struktur-Hack (danke an Joe Wreschnig für den Hinweis) bezeichnet.
Diese Syntax wurde jedoch erst kürzlich in C99 standardisiert (und die Effekte garantiert). Vorher war eine konstante Größe notwendig.
1
war der tragbare Weg, obwohl es ziemlich seltsam war.0
war besser in der Anzeige von Absichten, aber in Bezug auf den Standard nicht legal und wurde von einigen Compilern (einschließlich gcc) als Erweiterung unterstützt.Die Praxis der Schwanzpolsterung beruht jedoch auf der Tatsache, dass Speicher verfügbar ist (vorsichtig
malloc
) und daher im Allgemeinen nicht für die Stapelverwendung geeignet ist .quelle
int content[];
hier, soweit ich weiß . Da ich in Bezug auf C nicht allzu versiert bin ... können Sie bestätigen, ob meine Argumentation richtig erscheint?foo[x]
,foo[0]
wann immerfoo
ein Einzelelement-Array war.In Standard C und C ++ ist ein Array mit der Größe Null nicht zulässig.
Wenn Sie GCC verwenden, kompilieren Sie es mit der
-pedantic
Option. Es wird eine Warnung geben und sagen:Im Fall von C ++ gibt es eine ähnliche Warnung.
quelle
error C2466: cannot allocate an array of constant size 0
[BCC32 Error] test.c(3): E2021 Array must have at least one element
-pedantic -Werror
könnten Sie auch einfach tun-pedantic-errors
std::array
. (Nebenbei: Ich erinnere mich, kann aber die Quelle nicht finden, aus der VLAs in C ++ berücksichtigt und ausdrücklich abgelehnt wurden.)Es ist völlig illegal und war es schon immer, aber viele Compiler vernachlässigen es, den Fehler zu signalisieren. Ich bin mir nicht sicher, warum du das machen willst. Die einzige mir bekannte Verwendung besteht darin, einen Kompilierungszeitfehler von einem Booleschen Wert auszulösen:
Wenn dies
condition
falsch ist, wird ein Fehler bei der Kompilierung angezeigt. Da Compiler dies jedoch zulassen, habe ich Folgendes verwendet:Dies ergibt eine Größe von 1 oder -1, und ich habe noch nie einen Compiler gefunden, der eine Größe von -1 akzeptiert.
quelle
STATIC_ASSERT
es verwenden würden.#if condition \n #error whatever \n #endif
Ich werde hinzufügen, dass es zu diesem Argument eine ganze Seite der Online-Dokumentation von gcc gibt.
Einige Zitate:
und
so könntest du
und boom :-)
quelle
int a[0]
, danna[0] = 1
a[1] = 2
??a[100000] = 5
aber wenn Sie Glück haben, stürzen Sie Ihre App einfach ab, wenn Sie Glück haben: -)Eine andere Verwendung von Arrays mit der Länge Null besteht darin, Objekte mit variabler Länge (vor C99) zu erstellen. Nulllängen - Arrays sind verschieden von flexiblen Arrays denen [] ohne 0.
Zitiert aus gcc doc :
Ein Beispiel aus der Praxis sind Arrays mit der Länge Null
struct kdbus_item
in kdbus.h (einem Linux-Kernelmodul).quelle
void*
geeignet sind, und sie als arithmetische Zwecke betrachten (daher wäre das Hinzufügen oder Subtrahieren von Zeigern auf Objekte mit der Größe Null verboten). Während flexible Array-Mitglieder meistens besser sind als Arrays mit der Größe Null, können sie auch als eine Art "Vereinigung" von Alias-Dingen fungieren, ohne dem Folgenden eine zusätzliche Ebene der "syntaktischen" Indirektion hinzuzufügen (z. B. wennstruct foo {unsigned char as_bytes[0]; int x,y; float z;}
man auf Mitglieder zugreifen kann)x
.z
...myStruct.asFoo.x
usw. sagen zu müssen. Außerdem kreischt IIRC, C bei jedem Versuch, ein flexibles Array-Element in eine Struktur aufzunehmen, wodurch es unmöglich wird, eine Struktur zu haben, die mehrere andere flexible Array-Elemente bekannter Länge enthält Inhalt.sizeof x->contents
die ein Fehler in ISO C ist, im Gegensatz zur Rückgabe von 0 in gcc. Arrays mit der Größe Null, die keine Strukturelemente sind, führen zu einer Reihe anderer Probleme.struct {int n; THING dat[];}
und mit Dingen von statischer oder automatischer Dauer arbeiten kann.Array-Deklarationen mit der Größe Null innerhalb von Strukturen wären nützlich, wenn sie zulässig wären und wenn die Semantik so wäre, dass (1) sie die Ausrichtung erzwingen, aber ansonsten keinen Platz zuweisen würden, und (2) die Indizierung des Arrays als definiertes Verhalten in der Struktur betrachtet würde Fall, in dem sich der resultierende Zeiger im selben Speicherblock wie die Struktur befindet. Ein solches Verhalten wurde von keinem C-Standard zugelassen, aber einige ältere Compiler erlaubten es, bevor es zum Standard für Compiler wurde, unvollständige Array-Deklarationen mit leeren Klammern zuzulassen.
Der Struktur-Hack, wie er üblicherweise mit einem Array der Größe 1 implementiert wird, ist zweifelhaft und ich glaube nicht, dass Compiler es unterlassen müssen, ihn zu brechen. Zum Beispiel würde ich erwarten, dass ein Compiler, wenn er dies sieht
int a[1]
, in seinem Recht liegt, diesa[i]
als zu betrachtena[0]
. Wenn jemand versucht, die Ausrichtungsprobleme des Struktur-Hacks über so etwas zu umgehenEin Compiler könnte klug werden und davon ausgehen, dass die Array-Größe tatsächlich vier beträgt:
Eine solche Optimierung könnte sinnvoll sein, insbesondere wenn
myStruct->data
sie in derselben Operation wie in ein Register geladen werden könntemyStruct->size
. Ich weiß nichts in dem Standard, was eine solche Optimierung verbieten würde, obwohl es natürlich jeden Code brechen würde, der erwarten könnte, auf Dinge über das vierte Element hinaus zuzugreifen.quelle