Kann ein C-Compiler Stack-Variablen neu anordnen?

Lesezeit: 4 Minuten

Benutzer-Avatar
ryan_s

Ich habe in der Vergangenheit an Projekten für eingebettete Systeme gearbeitet, bei denen wir die Reihenfolge der Deklaration von Stack-Variablen neu angeordnet haben, um die Größe der resultierenden ausführbaren Datei zu verringern. Wenn wir zum Beispiel hätten:

void func()
{
    char c;
    int i;
    short s;
    ...
}

Wir würden dies neu anordnen:

void func()
{
    int i;
    short s;
    char c;
    ...
}

Aufgrund von Ausrichtungsproblemen führte der erste dazu, dass 12 Byte Stapelspeicherplatz verwendet wurden, und der zweite führte zu nur 8 Byte.

Ist dieses Standardverhalten für C-Compiler oder nur ein Mangel des verwendeten Compilers?

Es scheint mir, dass ein Compiler in der Lage sein sollte, Stack-Variablen neu zu ordnen, um eine kleinere ausführbare Größe zu bevorzugen, wenn er wollte. Mir wurde vorgeschlagen, dass ein Aspekt des C-Standards dies verhindert, aber ich konnte so oder so keine seriöse Quelle finden.

Gilt dies als Bonusfrage auch für C++-Compiler?

Bearbeiten

Wenn die Antwort ja lautet, können C/C++-Compiler Stack-Variablen neu anordnen. Können Sie ein Beispiel für einen Compiler geben, der dies definitiv tut? Ich würde gerne eine Compiler-Dokumentation oder etwas Ähnliches sehen, das dies unterstützt.

Erneut bearbeiten

Vielen Dank an alle für Ihre Hilfe. Zur Dokumentation ist das Papier das Beste, was ich finden konnte Optimale Stack-Slot-Zuweisung in GCC(pdf), von Naveen Sharma und Sanjiv Kumar Gupta, die 2003 auf dem GCC-Gipfel präsentiert wurde.

Das fragliche Projekt verwendete hier den ADS-Compiler für die ARM-Entwicklung. In der Dokumentation für diesen Compiler wird erwähnt, dass das Sortieren von Deklarationen, wie ich es gezeigt habe, die Leistung sowie die Stapelgröße verbessern kann, da die ARM-Thumb-Architektur Adressen im lokalen Stapelrahmen berechnet. Dieser Compiler hat Locals nicht automatisch neu angeordnet, um dies zu nutzen. Das hier verlinkte Papier besagt, dass GCC ab 2003 auch den Stapelrahmen nicht neu angeordnet hat, um die Referenzlokalität für ARM-Thumb-Prozessoren zu verbessern, aber es impliziert, dass Sie dies könnten.

Ich kann nichts finden, was definitiv besagt, dass dies jemals in GCC implementiert wurde, aber ich denke, dieses Papier gilt als Beweis dafür, dass Sie alle Recht haben. Danke noch einmal.

Der Compiler kann nicht nur das Stack-Layout der lokalen Variablen neu ordnen, er kann sie Registern zuweisen, sie zuweisen, manchmal in Registern und manchmal auf dem Stack zu leben, er kann zwei Lokale demselben Steckplatz im Speicher zuweisen (wenn ihre Live-Bereiche nicht überlappen) und es kann Variablen sogar vollständig eliminieren.

Benutzer-Avatar
Peterchen

Da der Standard dies für C- oder C++-Compiler nicht verbietet, ja, der Compiler kann das.

Bei Aggregaten (dh Strukturen) ist es anders, wo die relative Reihenfolge beibehalten werden muss, aber der Compiler dennoch Füllbytes einfügen kann, um eine bevorzugte Ausrichtung zu erreichen.

Neuere IIRC-MSVC-Compiler nutzen diese Freiheit in ihrem Kampf gegen Pufferüberläufe von Einheimischen.

Als Nebenbemerkung muss in C++ die Reihenfolge der Zerstörung die umgekehrte Reihenfolge der Deklaration sein, selbst wenn der Compiler das Speicherlayout neu ordnet.

(Ich kann Kapitel und Verse jedoch nicht zitieren, dies ist aus dem Gedächtnis.)

Benutzer-Avatar
Martin York

Dem Compiler steht es sogar frei, die Variable aus dem Stack zu entfernen und sie nur dann registrieren zu lassen, wenn die Analyse zeigt, dass die Adresse der Variablen niemals belegt/verwendet wird.

  • Das ist ein wirklich guter Punkt. Ich hatte nicht daran gedacht, als ich es mit meinem Kollegen besprach.

    – Ryan_s

    26. Oktober 2008 um 19:27 Uhr

  • Es kann sogar mehrere Variablen demselben Register- oder Stack-Speicherort zuweisen, wenn es beweisen kann, dass die Variablen niemals im selben Codeabschnitt aktiv sind. Dies ist gängige Praxis, insbesondere bei Inline-Code, der zu kurzen Variablenlebensdauern führt.

    – Ben Combee

    26. Oktober 2008 um 21:05 Uhr

Der Stack muss nicht einmal existieren (der C99-Standard hat kein einziges Vorkommen des Wortes “Stack”). Also ja, der Compiler kann tun, was er will, solange die Semantik von Variablen mit automatischer Speicherdauer erhalten bleibt.

Als Beispiel: Ich bin oft auf eine Situation gestoßen, in der ich eine lokale Variable im Debugger nicht anzeigen konnte, weil sie in einem Register gespeichert war.

Der Compiler für die Texas Instruments 62xx-Serie von DSPs ist in der Lage und führt eine “ganze Programmoptimierung” durch. ( du kannst es ausschalten)

Hier wird Ihr Code neu angeordnet, nicht nur die Einheimischen. Die Reihenfolge der Ausführung ist also nicht ganz das, was Sie vielleicht erwarten.

C und C++ nicht eigentlich versprechen ein Speichermodell (im Sinne von sagen wir der JVM), also kann es ganz anders und trotzdem legal sein.

Für diejenigen, die sie nicht kennen, die 62xx-Familie sind DSPs mit 8 Befehlen pro Taktzyklus; bei 750 MHz erreichen sie ihren Höhepunkt bei 6e+9 Anweisungen. Teilweise sowieso. Sie führen eine parallele Ausführung durch, aber die Befehlsreihenfolge erfolgt im Compiler, nicht in der CPU, wie bei einem Intel x86.

PICs und eingebettete Boards von Rabbit tun dies nicht haben Stapel, es sei denn, Sie fragen besonders nett.

Benutzer-Avatar
Will Dekan

Ein Compiler verwendet möglicherweise überhaupt keinen Stapel für Daten. Wenn Sie sich auf einer Plattform befinden, die so klein ist, dass Sie sich Sorgen um 8 vs. 12 Byte Stapel machen, dann ist es wahrscheinlich, dass es Compiler gibt, die ziemlich spezialisierte Ansätze haben. (Einige PIC- und 8051-Compiler fallen mir ein)

Für welchen Prozessor kompilierst du?

Benutzer-Avatar
CiNN

Es sind Compiler-Besonderheiten, man kann seinen eigenen Compiler machen, der das Gegenteil tun würde, wenn er es so wollte.

1146220cookie-checkKann ein C-Compiler Stack-Variablen neu anordnen?

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

Privacy policy