Was ist der Sinn von VLA überhaupt?

7

Ich verstehe, welche Arrays variabler Länge und wie sie implementiert sind. In dieser Frage geht es darum, warum sie existieren.

Wir wissen, dass VLAs nur innerhalb von Funktionsblöcken (oder Prototypen) erlaubt sind und dass sie grundsätzlich nicht irgendwo anders sein dürfen als auf dem Stack (unter der Annahme der normalen Implementierung): C11, 6.7.6.2-2:

  

Wenn ein Bezeichner als variabel veränderter Typ deklariert wird, soll er ein gewöhnlicher Bezeichner sein   Bezeichner (wie in 6.2.3 definiert), haben keine Verknüpfung und haben entweder einen Blockumfang oder eine Funktion   Prototypumfang. Wenn ein Bezeichner als Objekt mit statischem oder Thread-Speicher deklariert ist   Dauer, sollte es keinen Array-Typ variabler Länge haben.

Nehmen wir ein kleines Beispiel:

%Vor%

Es gibt zwei Fälle, die beachtet werden müssen:

  • n <= 0 : f muss sich dagegen wehren, sonst ist das Verhalten undefiniert: C11, 6.7.6.2-5 (Hervorhebung meins):

      

    Wenn die Größe ein Ausdruck ist, der kein ganzzahliger Konstantenausdruck ist: wenn er in a auftritt   Deklaration bei Funktionsprototyp Umfang, wird behandelt, als ob sie durch * ersetzt würde; Andernfalls,    Bei jeder Auswertung muss der Wert größer als null sein . Die Größe jeder Instanz   eines Array-Typs variabler Länge ändert sich nicht während seiner Lebensdauer. Wo eine Größe   Ausdruck ist Teil des Operanden eines sizeof - Operators und ändert den Wert von   Der Größenausdruck würde das Ergebnis des Operators nicht beeinflussen, es ist nicht spezifiziert, ob oder nicht   Der Größenausdruck wird ausgewertet.

  • n > stack_space_left / element_size : Es gibt keine Standardmethode, um herauszufinden, wie viel Stack-Speicherplatz noch übrig ist (da es keinen Stack gibt, solange der Standard betroffen ist). Also dieser Test ist unmöglich. Eine vernünftige Lösung ist nur eine vordefinierte maximale Größe für n , sagen wir N , um sicherzustellen, dass der Stack nicht überläuft.

Mit anderen Worten, der Programmierer muss 0 < n <= N für einige N der Wahl sicherstellen. Allerdings sollte das Programm trotzdem für n == N funktionieren, also könnte man das Array auch mit der konstanten Größe N und nicht mit der variablen Länge n deklarieren.

Mir ist bewusst, dass VLAs eingeführt wurden, um alloca zu ersetzen (wie auch in diese Antwort erwähnt), aber in Effekt sie sind die gleiche Sache (Speicher der variablen Größe auf Stapel zuweisen).

Es stellt sich also die Frage, warum alloca und folglich VLA existierten und warum wurden sie nicht abgeschrieben? Der einzige sichere Weg, um VLAs zu verwenden, scheint mir eine beschränkte Größe zu sein, in welchem ​​Fall die Verwendung eines normalen Arrays mit der maximalen Größe immer eine brauchbare Lösung ist.

    
Shahbaz 20.03.2014, 10:40
quelle

3 Antworten

12

Betrachtet man die Kommentare und die Antworten, so scheint mir, dass VLAs nützlich sind, wenn Sie wissen, dass Ihre Eingabe normalerweise nicht zu groß ist (ähnlich wie das Wissen, dass Ihre Rekursion wahrscheinlich nicht zu tief ist), aber eigentlich nicht eine obere Grenze, und Sie würden im Allgemeinen den möglichen Stapelüberlauf ignorieren (ähnlich dem Ignorieren sie mit Rekursion) in der Hoffnung, dass sie nicht passieren.

Es kann auch kein Problem sein, zum Beispiel, wenn Sie eine unbegrenzte Stapelgröße haben.

Das heißt, hier ist eine andere Verwendung für sie, die ich gefunden habe, die nicht wirklich Speicher auf Stack zuweist, sondern das Arbeiten mit dynamischen mehrdimensionalen Arrays erleichtert. Ich demonstriere anhand eines einfachen Beispiels:

%Vor%     
Shahbaz 19.01.2015, 10:32
quelle
4

Trotz all der Punkte, die Sie über VLA erwähnt haben, ist der beste Teil von VLA, dass der Compiler automatisch die Speicherverwaltung und die Komplexität von Indexberechnungen von Arrays behandelt, deren Grenzen keine Kompilierzeitkonstanten sind Wenn Sie eine lokale dynamische Speicherzuweisung wünschen, ist VLA die einzige Option.

Ich denke, das könnte der Grund dafür sein, dass VLA in C99 übernommen wird (optional zu C11).

Eines möchte ich klarstellen: Es gibt einige bemerkenswerte Unterschiede zwischen alloca und VLA . Dieser Beitrag weist auf die Unterschiede hin:

  
  • Der Speicher alloca() gibt zurück, solange die aktuelle Funktion fortbesteht. Die Lebensdauer des von einem VLA belegten Speichers ist solange gültig, wie der Identifikator des VLA im Gültigkeitsbereich bleibt.
  •   
  • Sie können zum Beispiel alloca() Speicher in einer Schleife verwenden und den Speicher außerhalb der Schleife verwenden, ein VLA wäre weg, weil der Bezeichner den Gültigkeitsbereich verlässt, wenn die Schleife beendet wird.
  •   
    
haccks 20.03.2014 10:50
quelle
3

Ihr Argument scheint zu sein, dass, da man die Größe des VLA überprüfen muss, warum nicht einfach die maximale Größe zuweisen und mit der Laufzeitzuweisung fertig sein muss.

Dieses Argument übersieht die Tatsache, dass Speicher eine begrenzte Ressource im System ist, die von vielen Prozessen gemeinsam genutzt wird. Speicher, der in einem Prozess verschwendet wird, ist für andere nicht verfügbar (oder ist es vielleicht, aber auf Kosten des Austausches auf die Festplatte).

Mit demselben Argument würden wir zur Laufzeit kein Array malloc benötigen, wenn wir die maximal mögliche Größe statisch zuordnen könnten. Am Ende ist Heap Erschöpfung nur wenig vorzuziehen, Stack Überlauf.

    
harmic 20.03.2014 11:13
quelle

Tags und Links