Warum platzieren C- und C++-Compiler explizit initialisierte und standardmäßig initialisierte globale Variablen in verschiedenen Segmenten?

Lesezeit: 5 Minuten

Benutzer-Avatar
Destruktor

ich habe gelesen diesen großartigen Beitrag über das Speicherlayout von C-Programmen. Es besagt, dass sich standardmäßig initialisierte globale Variablen in der befinden BSS-Segmentund wenn Sie einer globalen Variablen explizit einen Wert zuweisen, befindet sich dieser in der Datensegment.

Ich habe die folgenden Programme in C und C++ getestet, um dieses Verhalten zu untersuchen.

#include <iostream>
// Both i and s are having static storage duration
int i;     // i will be kept in the BSS segment, default initialized variable, default value=0
int s(5);  // s will be kept in the data segment, explicitly initialized variable,
int main()
{
    std::cout<<&i<<' '<<&s;
}

Ausgabe:

0x488020 0x478004

Aus der Ausgabe sieht es also eindeutig so aus, als ob sich beide Variablen i & s in völlig unterschiedlichen Segmenten befinden. Aber wenn ich den Initialisierer (Anfangswert 5 in diesem Programm) aus der Variablen S entferne und dann das Programm ausführe, erhalte ich die folgende Ausgabe.

Ausgabe:

0x488020 0x488024

Aus der Ausgabe sieht es also eindeutig so aus, als ob sich beide Variablen i und s im selben Segment (in diesem Fall BSS) befinden.

Dieses Verhalten ist auch in C gleich.

#include <stdio.h>
int i;      // i will be kept in the BSS segment, default initialized variable, default value=0
int s=5;    // s will be kept in the data segment, explicitly initialized variable,
int main(void)
{
    printf("%p %p\n",(void*)&i,(void*)&s);
}

Ausgabe:

004053D0 00403004

Also können wir wieder sagen, indem wir uns die Ausgabe ansehen (d. h. die Adresse der Variablen untersuchen), dass sich sowohl die Variablen i als auch s in völlig unterschiedlichen Segmenten befinden. Aber noch einmal, wenn ich den Initialisierer (Anfangswert 5 in diesem Programm) aus der Variablen S entferne und dann das Programm ausführe, erhalte ich die folgende Ausgabe.

Ausgabe:

004053D0 004053D4

Aus der Ausgabe sieht es also eindeutig so aus, als ob sich beide Variablen i und s im selben Segment (in diesem Fall BSS) befinden.

Warum platzieren C- und C++-Compiler explizit initialisierte und standardmäßig initialisierte globale Variablen in verschiedenen Segmenten? Warum wird zwischen standardmäßig initialisierten und explizit initialisierten Variablen unterschieden, wo sich die globale Variable befindet? Wenn ich mich nicht irre, sprechen die C- und C++-Standards nie über Stack, Heap, Datensegment, Codesegment, BSS-Segment und all solche Dinge, die implementierungsspezifisch sind. Ist es also für eine C++-Implementierung möglich, explizit initialisierte und standardmäßig initialisierte Variablen in denselben Segmenten zu speichern, anstatt sie in verschiedenen Segmenten zu halten?

  • .bss: “Normalerweise wird nur die Länge des bss-Abschnitts, aber keine Daten, in der Objektdatei gespeichert … Betriebssysteme können eine Technik namens Zero-Fill-on-Demand verwenden, um das bss-Segment effizient zu implementieren.”

    – Damien_Der_Ungläubige

    19. Dezember 2015 um 7:06 Uhr

  • Fühlen Sie sich privilegiert … Ich musste einmal einen Compiler verwenden, der statische Variablen einfügt .data wenn sie es hätten = 0 Initialisierer und in .bss wenn sie keinen Initialisierer hätten. Außerdem musste dieselbe Codebasis auf einem anderen (kaputten) Compiler verwendet werden, der statische Variablen, die keinen Initialisierer hatten, nicht mit Null initialisierte.

    – MM

    19. Dezember 2015 um 8:45 Uhr

  • Trivia-Quiz: Was bedeutet BSS?

    – Peter Becker

    19. Dezember 2015 um 16:59 Uhr

  • Es steht für Block gestartet durch Symbol.

    – 500 – Interner Serverfehler

    20. Dezember 2015 um 0:11 Uhr

Weder die Sprache C noch C ++ haben einen Begriff von “Segmenten”, und auch nicht alle Betriebssysteme, sodass Ihre Frage zwangsläufig von der Plattform und dem Compiler abhängt.

Allerdings behandeln gängige Implementierungen initialisierte und nicht initialisierte Variablen unterschiedlich. Der Hauptunterschied besteht darin, dass nicht initialisierte (oder standardmäßig 0-initialisierte) Daten dies tun nicht müssen eigentlich nur mit dem kompilierten Modul gespeichert werden deklariert/reserviert zur späteren Verwendung zur Laufzeit. In praktischen “Segment”-Begriffen initialisierte Daten ist als Teil der Binärdatei auf der Festplatte gespeichert, während nicht initialisierte Daten nichtstattdessen wird es beim Start zugewiesen, um die deklarierten “Reservierungen” zu erfüllen.

Die wirklich kurze Antwort ist “weil es weniger Platz einnimmt”. (Wie von anderen angemerkt, muss der Compiler dies nicht tun!)

In der ausführbaren Datei ist die data -Abschnitt enthält Daten, deren Wert an der entsprechenden Stelle gespeichert ist. Das bedeutet, dass für jedes Byte initialisierter Daten dieser Datenabschnitt ein Byte enthält.

Für nullinitialisierte Globale gibt es keinen Grund, viele Nullen zu speichern. Speichern Sie stattdessen einfach die Größe des gesamten Datensatzes in einem einzigen Größenwert. Anstatt also 4132 Bytes Null in der zu speichern data seciton gibt es nur ein “BSS ist 4132 Byte lang” – und es liegt am Betriebssystem / der Laufzeit, es so einzurichten, dass es null ist. – in einigen Fällen wird die Laufzeit des Compilers memset(BSSStart, 0, BSSSize) oder ähnliches. In Linux wird beispielsweise der gesamte “nicht verwendete” Speicher ohnehin mit Null gefüllt, wenn der Prozess erstellt wird. Wenn Sie also BSS auf Null setzen, müssen Sie den Speicher überhaupt erst zuweisen.

Und natürlich haben kürzere ausführbare Dateien mehrere Vorteile: Weniger Speicherplatz auf Ihrer Festplatte, schnellere Ladezeit [extra bonus if the OS pre-fills the allocated memory with zero]schnellere Kompilierzeit, da der Compiler/Linker die Daten nicht auf die Festplatte schreiben muss.

Das hat also einen ganz praktischen Grund.

Benutzer-Avatar
masud

Per Definition ist BSS kein anderes Segment, sondern ein Teil des Datensegments.

In C und C++ werden statisch zugewiesene Objekte ohne expliziten Initialisierer auf null initialisiert, eine Implementierung kann auch statisch zugewiesene Variablen und Konstanten zuweisen, die mit einem Wert initialisiert wurden, der ausschließlich aus nullwertigen Bits besteht BSS-Sektion.

Ein Grund, sie in BSS zu speichern, ist, dass diese Arten von Variablen mit nicht initialisierten oder Standardwerten zur Laufzeit abgerufen werden können, ohne Platz in den Binärdateien zu verschwenden, anstatt die Variablen, die im Datensegment platziert sind.

1369140cookie-checkWarum platzieren C- und C++-Compiler explizit initialisierte und standardmäßig initialisierte globale Variablen in verschiedenen Segmenten?

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

Privacy policy