Lokale und statische Variablen in C

Lesezeit: 6 Minuten

Benutzer-Avatar
Lefteris Laskaridis

Beim Kompilieren:

// external definitions
int value1 = 0;
static int value2 = 0;

Der gcc-Compiler generiert die folgende Assembly:

.globl value1
        .bss
        .align 4
        .type   value1, @object
        .size   value1, 4
value1:
        .zero   4
        .local  value2
        .comm   value2,4,4

Wenn ich jedoch die Variablen auf einen anderen Wert als Null initialisiere, wie zum Beispiel:

// external definitions
int value1 = 1;
static int value2 = 1;

Der gcc-Compiler generierte Folgendes:

.globl value1
        .data
        .align 4
        .type   value1, @object
        .size   value1, 4
value1:
        .long   1
        .align 4
        .type   value2, @object
        .size   value2, 4
value2:
        .long   1

Meine Fragen sind:

  1. Warum werden im ersten Fall die Werte im bss-Segment und im zweiten Fall im Datensegment zugewiesen?
  2. Warum die Variable value2 im ersten Fall als .local und .comm definiert ist, im zweiten nicht.

  • An Ihrem C-Code-Snippet ist es jedoch schwer zu erkennen value1 scheint eine globale Variable zu sein (eher als eine lokale). Eine lokale Variable würde auf dem Stapel zugewiesen werden.

    – Kodo

    27. November 2012 um 9:31 Uhr

  • Schwer zu sagen. Ich würde mir überlegen, das einzubauen .bss ein Käfer. Es gibt zwar keinen Unterschied zur Ansicht des Standards (nicht initialisierte Variablen sollten initialisiert werden 0), es hat sich gelohnt, dass init’ing zu 0 unterscheidet sich davon, nicht initialisiert zu sein.

    – glglgl

    27. November 2012 um 9:33 Uhr

  • @Codo beide Variablendefinitionen in meinen Snippets sind externe Definitionen und keine lokalen.

    – Lefteris Laskaridis

    27. November 2012 um 9:33 Uhr

  • @lefty: Was Sie damit meinen, ist, dass sie im Dateibereich definiert sind. (Im Gegensatz zu Blockumfang, Funktionsumfang usw.) Intern / Extern sind Fachbegriffe mit spezifischen Definitionen, die etwas anderes bedeuten.

    – Dietrich Ep

    27. November 2012 um 9:40 Uhr


  • @glglgl: Aber es ist falsch zu sagen, dass Null-initialisierte Daten eingefügt werden .bss ist ein Fehler. Sicher, auf einigen Systemen können Sie den Compiler dazu zwingen, sich nicht standardkonform zu verhalten, aber das ist nicht wirklich relevant.

    – Dietrich Ep

    27. November 2012 um 9:43 Uhr


Benutzer-Avatar
iabdalkader

Allgemein gesagt, die bss Abschnitt enthält nicht initialisierte Werte und die data Abschnitt enthält initialisierte Werte. gcc platziert jedoch Werte, die auf Null initialisiert wurden, in die bss Abschnitt statt der data Abschnitt, wie die bss Abschnitt zur Laufzeit ohnehin auf Null gesetzt wird, macht es wenig Sinn, Nullen in zu speichern data Abschnitt, spart dies etwas Speicherplatz, von man gcc:

-fno-zero-initialized-in-bss Wenn das Ziel einen BSS-Abschnitt unterstützt, GCC legt standardmäßig auf Null initialisierte Variablen in BSS ab. Dies kann Platz im resultierenden Code sparen. Diese Option schaltet dieses Verhalten aus, da einige Programme explizit auf Variablen angewiesen sind, die in den Datenabschnitt gehen

Ich bin mir nicht sicher warum .comm wird mit verwendet statisch Speicher, der für eine Objektdatei lokal ist, wird er normalerweise verwendet, um allgemeine Symbole zu deklarieren, die, wenn nicht definiert/initialisiert, sollte vom Linker mit gleichnamigen Symbolen aus anderen Objektdateien zusammengeführt werden und wird deshalb im zweiten Beispiel nicht verwendet, da die Variablen initialisiert werden, aus der as Handbuch

.comm deklariert ein gemeinsames Symbol namens symbol. Beim Verknüpfen kann ein gemeinsames Symbol in einer Objektdatei mit einem definierten oder gemeinsamen Symbol mit demselben Namen in einer anderen Objektdatei zusammengeführt werden

  • Irgendwelche Ideen zum zweiten Teil meiner Frage?

    – Lefteris Laskaridis

    27. November 2012 um 9:35 Uhr

  • @lefty: Deshalb ist es keine gute Idee, zwei Fragen in einer auf Stack Overflow zu stellen. Sie können nicht zwei Antworten auswählen.

    – Dietrich Ep

    27. November 2012 um 9:37 Uhr


  • Zu sagen, dass BSS nicht initialisierte Daten enthält, ist ein wenig irreführend, da es tatsächlich zur Laufzeit initialisiert wird. Der Unterschied besteht hauptsächlich darin, ob dies in der Programmbinärdatei zur Kompilierzeit oder zur Laufzeit erfolgt.

    – fkl

    27. November 2012 um 9:55 Uhr

  • @fayyazkl Ich habe gesagt, dass es zur Laufzeit initialisiert wird.

    – iabdalkader

    27. November 2012 um 9:59 Uhr

  • @mux Ich stimme zu. Hervorheben nur die Initialisierung. Ich habe tatsächlich Ihre erste Antwort gesehen, in der ich das Gefühl hatte, dass der Laufzeitinitialisierungsteil nicht erwähnt wurde. Also fing ich an, einen zu schreiben. Letzteres habe ich nach der Bearbeitung gesehen.

    – fkl

    27. November 2012 um 10:03 Uhr

Der erste Fall liegt daran, dass Sie die Werte mit Null initialisiert haben. Es ist Teil der C-Standard (Abschnitt 6.7.8), dass eine globale Ganzzahl mit 0 initialisiert wird, wenn keine angegeben ist. Dateiformate haben also eine Vorkehrung getroffen, um Binärdateien kleiner zu halten, indem sie einen speziellen Abschnitt haben, in dem diese platziert werden: bss. Wenn Sie sich einige ansehen ELF-Spezifikation (auf Seite I-15) finden Sie Folgendes:

.bss Dieser Abschnitt enthält nicht initialisierte Daten, die zum Speicherabbild des Programms beitragen. Per Definition initialisiert das System die Daten mit Nullen, wenn das Programm zu laufen beginnt. Der Abschnitt belegt keinen Dateispeicherplatz, wie durch den Abschnittstyp SHT_NOBITS angegeben.

Im ersten Fall hat der Compiler eine Optimierung vorgenommen. Es muss keinen Platz in der eigentlichen Binärdatei einnehmen, um den Initialisierer zu speichern, da es die verwenden kann bss segmentieren und erhalten Sie das gewünschte kostenlos.

Nun, die Tatsache, dass Sie ein Rauschen von einer externen Quelle haben, ist ein bisschen interessant (es wird normalerweise nicht gemacht). In dem zu kompilierenden Modul sollte dies jedoch nicht mit anderen Modulen geteilt und mit gekennzeichnet werden .local. Ich vermute, dass dies auf diese Weise geschieht, da kein tatsächlicher Wert für den Initialisierer gespeichert werden muss.

Da Sie im zweiten Beispiel einen Nicht-Null-Initialisierer angegeben haben, wissen Sie, dass er sich im initialisierten Datensegment befindet data. value1 sieht sehr ähnlich aus, aber für value2, muss der Compiler Platz für den Initialisierer reservieren. In diesem Fall muss es nicht als gekennzeichnet werden .local weil es einfach den Wert festlegen und damit fertig sein kann. Es ist nicht global, weil es keine gibt .globl Aussage dazu.

Übrigens, http://refspecs.linuxbase.org/ ist ein guter Ort, um einige der Low-Level-Details über Binärformate und dergleichen zu besuchen.

Benutzer-Avatar
fkl

BSS ist das Segment, das Daten enthält, die bei initialisiert wurden Laufzeit wobei ein Datensegment Daten enthält, die in initialisiert wurden binär programmieren.

Jetzt werden statische Variablen immer initialisiert, unabhängig davon, ob dies explizit im Programm erfolgt oder nicht. Aber es gibt zwei getrennte Kategorien, initialisierte (DS) und nicht initialisierte (BSS) Statik.

Alle in BSS vorhandenen Werte sind diejenigen, die nicht im Programmcode initialisiert werden und daher initialisiert werden, wenn das Programm zur Laufzeit auf 0 (falls Ganzzahl), Null für Zeiger usw. geladen wird.

Wenn Sie also mit 0 initialisieren, geht der Wert an BSS, wo wie jeder andere zugewiesene Wert die Variable im Datensegment zuweist.

Eine interessante Konsequenz ist, Die Größe der in BSS initialisierten Daten wird nicht in die Programmbinärdatei aufgenommen, wohingegen die Größe der Daten im Datensegment enthalten ist.

Versuchen Sie, ein großes statisches Array zuzuweisen und es in einem Programm zu verwenden. Sehen Sie sich die Größe der ausführbaren Datei an, wenn sie nicht explizit im Code initialisiert wird. Initialisieren Sie es dann mit Nicht-Null-Werten wie

static int arr[1000] = {2};

Die Größe der ausführbaren Datei ist im letzteren Fall erheblich größer

1157810cookie-checkLokale und statische Variablen in C

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

Privacy policy