Warum ist die Größe eines Arrays als konstante Variable in C nicht erlaubt, aber in C++ erlaubt?

Lesezeit: 6 Minuten

Benutzer-Avatar
kadin

Ich habe versucht, ein AC-Programm wie folgt zu schreiben?

const int x = 5;

int main()
{
    int arr[x] = {1, 2, 3, 4, 5};
}

Dies gibt Warnungen aus, wenn ich versucht habe, mit gcc wie unten zu kompilieren.

simple.c:9: Fehler: Objekt mit variabler Größe kann nicht initialisiert werden.

Aber das gleiche ist in C++ erlaubt. Wenn ich x als Arraygröße übergebe, warum wird x nicht als Konstante behandelt?

  • Weil die Designer von C entschieden haben, dass es nicht als konstant behandelt werden sollte

    – MM

    18. September 2014 um 0:50 Uhr

  • Die Designer von Sprachen können festlegen, was richtig und was falsch ist. C ist nicht nur eine Teilmenge von C++. Die beiden Sprachen sind verschieden. Die Regel von C macht die Arbeit des Compilers etwas einfacher. Das ist wahrscheinlich der Grund für den Unterschied, aber es ist nur eine Vermutung.

    – Gen

    18. September 2014 um 0:51 Uhr


  • @MattMcNabb fairer Punkt, fügte relevante Details hinzu, die dies ebenfalls erklären.

    – Shafik Yaghmour

    18. September 2014 um 1:49 Uhr

Benutzer-Avatar
Keith Thompson

In C const bedeutet nicht “konstant” (dh zur Kompilierzeit auswertbar). Es bedeutet lediglich schreibgeschützt.

Zum Beispiel innerhalb einer Funktion:

const int r = rand();
const time_t now = time(NULL);

ist vollkommen gültig.

Der Name eines Objekts, definiert als const int ist kein ständiger Ausdruck. Das bedeutet, dass es (in C vor C99 und in allen Versionen von C++) nicht verwendet werden kann, um die Länge eines Arrays zu definieren.

Obwohl C99 (und optional C11) unterstützt wird Arrays mit variabler Länge (VLAs), sie können nicht initialisiert werden. Im Prinzip kennt der Compiler die Größe eines VLA nicht, wenn es definiert ist, also kann er nicht prüfen, ob ein Initialisierer gültig ist. In Ihrem speziellen Fall ist der Compiler wahrscheinlich in der Lage, es herauszufinden, aber die Sprachregeln sind so konzipiert, dass sie den allgemeineren Fall abdecken.

C++ ist fast das gleiche, aber C++ hat eine spezielle Regel, die C fehlt: Wenn ein Objekt als definiert ist constund seine Initialisierung ist ein konstanter Ausdruck, dann ist der Name des Objekts selbst ein konstanter Ausdruck (zumindest für ganzzahlige Typen).

Es gibt keinen wirklich guten Grund, warum C diese Funktion nicht übernommen hat. Wenn Sie in C eine Namenskonstante vom Typ Integer benötigen, verwenden Sie normalerweise ein Makro:

 #define LEN 5
 ...
 int arr[LEN] = {1, 2, 3, 4, 5};

Beachten Sie, dass, wenn Sie den Wert von ändern LENmüssen Sie den Initialisierer neu schreiben.

Ein weiterer Ansatz ist die Verwendung eines anonymen enum:

 enum { LEN = 5 };
 ...
 int arr[LEN] = {1, 2, 3, 4, 5};

Der Name einer Aufzählungskonstante ist eigentlich ein konstanter Ausdruck. In C ist es aus historischen Gründen immer vom Typ int; in C++ ist es vom Aufzählungstyp. Leider funktioniert dieser Trick nur für Konstanten vom Typ intalso ist es auf Werte im Bereich von beschränkt INT_MIN zu INT_MAX.

  • “Wenn ein Objekt als konstant definiert ist und seine Initialisierung ein konstanter Ausdruck ist, dann ist der Name des Objekts selbst ein konstanter Ausdruck.” Ich denke nicht, dass das richtig ist. Siehe: stackoverflow.com/a/13347355/866732

    – WiSaGaN

    18. September 2014 um 1:10 Uhr

  • @WiSaGaN: Ich glaube, es gilt zumindest für ganzzahlige Typen. Ein schnelles Experiment zeigt das Gegebene const int five = 5;Ich kann nutzen case five: in einer switch-Anweisung (unter Verwendung von g++ 4.8.2 mit -pedantic und viele Warnungen aktiviert). Ich bin mir der Regeln für Gleitkommazahlen nicht sicher. Ich habe meine Antwort aktualisiert, um auf integrale Typen zu verweisen.

    – Keith Thompson

    18. September 2014 um 1:14 Uhr


Wenn ich x als Arraygröße übergebe, warum wird x nicht als Konstante behandelt?

Denn in C können konstante Ausdrücke nicht einmal die Werte von Variablen enthalten const Einsen. (Dies ist einer der Gründe, warum C so abhängig von Makrokonstanten ist, während C++ verwenden würde const Variablen für den gleichen Zweck.)

Auf der anderen Seite in C++, x wäre sicherlich ein konstanter Ausdruck if x wird als deklariert const int x = 5;.

Wenn Ihre Frage ist warum C++ ist so viel liberaler als C, wenn es um konstante Ausdrücke geht, ich denke, es dient der Unterstützung der Metaprogrammierung und der Durchführung komplexer Berechnungen zur Kompilierzeit mithilfe von Vorlagen.

Benutzer-Avatar
Shafik Yaghmur

Ich denke fast jeder hat den Fehler missverstanden, der Fehler sagt:

Objekt mit variabler Größe darf nicht initialisiert werden.

was richtig ist, C99 und C11(obwohl sie in C11 optional sind). Sie können in der Deklaration nicht initialisiert werden, wir können dies aus Abschnitt sehen 6.7.8 Initialisierung:

Es wird als VLA behandelt, da C im Gegensatz zu C++ eine erwartet ganzzahliger konstanter Ausdruck:

Wenn die Größe ein ganzzahliger konstanter Ausdruck ist und der Elementtyp eine bekannte konstante Größe hat, ist der Array-Typ kein Array-Typ mit variabler Länge;

und ein ganzzahliger konstanter Ausdruck hat die folgenden Einschränkungen:

muss vom Typ Integer sein und darf nur Operanden haben, die Integer-Konstanten, Aufzählungskonstanten, Zeichenkonstanten, sizeof-Ausdrücke, deren Ergebnisse Integer-Konstanten sind, und Floating-Konstanten haben, die die unmittelbaren Operanden von Umwandlungen sind. Cast-Operatoren in einem ganzzahligen konstanten Ausdruck konvertieren nur arithmetische Typen in ganzzahlige Typen, außer als Teil eines Operanden für den sizeof-Operator.

die x befriedigt nicht.

Der Typ der zu initialisierenden Entität muss ein Array unbekannter Größe oder ein Objekttyp sein, der kein Array-Typ mit variabler Länge ist.

In C++ ist dies kein Array mit variabler Länge, da x gilt als ein ständiger Ausdruck und wir können, dass dies aus dem Entwurf des C++-Standardabschnitts gültig ist 8.3.4 Arrays unter Abschnitt 8 Deklaratoren was sagt:

In einer Deklaration TD, wobei D die Form hat

 D1 [ constant-expressionopt] attribute-specifier-seqopt

[…]Wenn der Konstantenausdruck (5.19) vorhanden ist, muss er ein konvertierter konstanter Ausdruck vom Typ std::size_t sein und sein Wert muss größer als Null sein. Der konstante Ausdruck gibt die Grenze (Anzahl der Elemente in) des Arrays an. Wenn der Wert des konstanten Ausdrucks N ist, hat das Array N Elemente, die von 0 bis N-1 nummeriert sind[…]

Wenn wir die entfernen konst aus der Erklärung v x Es würde aus einem von zwei Gründen fehlschlagen, entweder unterstützt der Compiler VLA als Erweiterung und es würde aus demselben Grund fehlschlagen, aus dem es in C fehlschlägt, oder der Compiler unterstützt VLA nicht als Erweiterung und daher wäre die Deklaration nicht gültig.

  • Nicht jeder; Ich habe es in meiner Antwort erwähnt. Und ein großer Teil des Problems ist warum arr wird als Objekt variabler Größe behandelt.

    – Keith Thompson

    18. September 2014 um 1:16 Uhr


  • @KeithThompson oh ja, das sehe ich jetzt, deine Antworten fangen wie alle anderen an und deshalb habe ich das verpasst.

    – Shafik Yaghmour

    18. September 2014 um 1:21 Uhr

Ich gehe davon aus, dass Sie einen C99-Compiler verwenden (der Arrays mit dynamischer Größe unterstützt). Was passiert ist, dass der Compiler während der Kompilierung nicht sicher wissen kann, wie sich Ihr Array in Bezug auf den Speicher verhalten wird.

Versuche dies:

int arr[x];
memset( arr, 0, x*sizeof(int) );

und sehen, ob es funktioniert.

Eine andere Sache, von der ich denke, dass sie dies verursachen könnte, ist, dass const nicht wirklich etwas unter der Haube bedeutet, und der Compiler Sie deshalb möglicherweise nicht das tun lässt, was Sie versuchen. Sie sehen, es gibt mehrere Möglichkeiten, const-Variablen zu ändern, und das ist einer der Gründe, warum c# zum Beispiel das const-Schlüsselwort nicht präsentiert. const ist eher eine Warnung für Menschen als alles andere.

1015920cookie-checkWarum ist die Größe eines Arrays als konstante Variable in C nicht erlaubt, aber in C++ erlaubt?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy