2010-07-30 11 views
8

Mögliche Duplizieren:
Why global and static variables are initialized to their default values?Warum werden statische Variablen automatisch auf Null initialisiert?

Was ist der technische Grund dies geschieht? Und wird es vom Standard auf allen Plattformen unterstützt? Ist es möglich, dass bestimmte Implementierungen nicht definierte Variablen zurückgeben, wenn statische Variablen nicht explizit initialisiert werden?

+2

Gewählt, um wieder zu öffnen, weil diese Frage auch fragt, ob einige Compiler statische Variablen nicht auf null setzen. Die Antwort ist ja! Einige domänenspezifische Compiler entsprechen nicht allen Standards. Zum Beispiel wird in TIGCC (ein C-Compiler für TI-89/92/V200-Rechner) eine globale Variable mit einer expliziten Initialisierung (z. B. 'static int high_score = 0; ') über die Programmdurchläufe hinweg erhalten (sofern sie nicht archiviert ist) im Flash-Speicher), bietet eine einfache aber schmierige Möglichkeit, Programmeinstellungen zu behalten. –

Antwort

31

Es ist von der Norm gefordert (§6.7.8/10).

Es gibt keinen technischen Grund dafür, zu haben, um so zu sein, aber es ist so lang genug gewesen, dass das Standardkomitee es eine Voraussetzung bildete.

Das Auslassen dieser Anforderung würde das Arbeiten mit statischen Variablen in vielen (meist?) Fällen etwas schwieriger machen. Insbesondere müssen Sie oft eine einmalige Initialisierung durchführen und benötigen einen zuverlässigen Startzustand, damit Sie wissen, ob eine bestimmte Variable bereits initialisiert wurde oder nicht. Zum Beispiel:

int foo() { 
    static int *ptr; 

    if (NULL == ptr) 
     // initialize it 
} 

Wenn ptr einen beliebigen Wert beim Start enthalten könnte, dann würden Sie müssen es explizit initialisieren, um die Lage sein, NULL zu erkennen, ob Sie Ihre einmalige getan haben Initialisierung noch oder nicht.

+1

+1 für die Standards Link. Das ursprüngliche Mandat des ANSI C-Komitees bestand darin, die bestehende Praxis zu kodifizieren, aus der sich wahrscheinlich die Notwendigkeit ergibt. – paxdiablo

+3

@paxdiablo: Zweifellos - es ist explizit in K & R1 (Anhang A, §6) angegeben.8): "Statische und externe Variablen, die nicht initialisiert sind, werden garantiert als 0 gestartet; automatische und Register-Variablen, die nicht initialisiert sind, werden garantiert als Abfall gestartet." –

0

Hauptsächlich, weil die statischen Variablen in einem Block vom Linker gruppiert werden, so ist es wirklich einfach, nur den gesamten Block beim Start auf memset() zu setzen. Ich glaube nicht, dass dies von den C- oder C++ - Standards gefordert wird.

+1

Es ist nicht "memset" auf 0, außer auf DOS und anderen [Nicht-] Betriebssystemen. Auf einem modernen System ist es eine Kopie-auf-Schreib-Referenz auf die "Nullseite". –

0

Es Diskussion über diese here ist:

allererst in ISO C (ANSI C), alle statischen und globalen Variablen müssen initialisiert werden, bevor das Programm startet. Wenn der Programmierer das nicht explizit getan hat, muss der Compiler sie auf Null setzen. Wenn der Compiler dies nicht tut, folgt er nicht ISO C. Genau wie die Variablen initialisiert werden, ist jedoch vom Standard nicht spezifiziert.

0

Werfen Sie einen Blick: here 6.2.4 (3) und 6.7.8 (10)

9

Ja, es ist, weil es in der Norm ist; aber wirklich, weil es kostenlos ist. Statische Variablen sehen für den generierten Objektcode genauso aus wie globale Variablen. Sie werden in .bss zugewiesen und zur Ladezeit zusammen mit all Ihren Konstanten und anderen globalen Variablen initialisiert. Da der Speicherbereich, in dem sie sich befinden, nur direkt von Ihrer ausführbaren Datei kopiert wird, wird sie mit einem Wert initialisiert, der zur Kompilierungszeit kostenlos bekannt ist. Der gewählte Wert ist 0.

+1

Der Abschnitt .bss in ELF-Dateien hat die Länge null. Es ist der Lader, der dafür verantwortlich ist, den Block zu initialisieren. Wenn dies vom Standard nicht benötigt wird, kann der Block nicht initialisiert werden. – doron

+5

Eine nicht initialisierte Seite beim Start des Prozesses wäre ohnehin "all-zero", es sei denn, der Kernel versucht, zufälligen Datenmüll zu schreiben. Bei jeder modernen Implementierung ist bss eine COW-Referenz (Copy-on-Write) auf die "Zero Page", die von allen Prozessen gemeinsam genutzt wird. Selbst wenn dies nicht der Fall wäre, müsste der Kernel dennoch etwas unternehmen, um zu verhindern, dass neue Prozesse den Inhalt von zufälligem physischem Speicher sehen (der private interne Kernel-Daten oder Daten von anderen Benutzern enthalten kann) nützlicher Wert wie 0 beim Löschen ... –

0

Angenommen, Sie haben einen C-Compiler geschrieben. Sie erwarten, dass einige statische Variablen anfängliche Werte haben, daher müssen diese Werte irgendwo in der ausführbaren Datei erscheinen, die der Compiler erstellen wird. Wenn jetzt das Ausgabeprogramm ausgeführt wird, wird die gesamte ausführbare Datei in den Speicher geladen. Ein Teil der Initialisierung des Programms besteht darin, die statischen Variablen zu erzeugen, so dass alle diese Anfangswerte in ihre endgültigen statischen Variablenziele kopiert werden müssen.

Oder sie? Sobald das Programm startet, werden die Anfangswerte der Variablen nicht mehr benötigt. Können die Variablen selbst nicht innerhalb des ausführbaren Codes selbst liegen? Dann müssen die Werte nicht kopiert werden.Die statischen Variablen könnten in einem Block existieren, der sich in der ursprünglichen ausführbaren Datei befand, und für sie muss überhaupt keine Initialisierung durchgeführt werden.

Wenn das der Fall ist, warum möchten Sie dann einen speziellen Fall für nicht initialisierte statische Variablen machen? Warum nicht einfach einen Haufen Nullen in die ausführbare Datei einfügen, um die nicht initialisierten statischen Variablen darzustellen? Das würde für etwas Zeit und viel weniger Komplexität etwas Platz tauschen.

Ich weiß nicht, ob ein C-Compiler tatsächlich auf diese Weise verhält, aber ich vermute, dass die Möglichkeit, Dinge auf diese Weise zu tun, das Design der Sprache beeinflusst haben könnte.

+0

Einige alte C-Compiler haben möglicherweise initialisierte Variablen in das Codebild eingefügt und haben von dort aus darauf zugegriffen. Ich weiß, Turbo Pascal hat das gemacht. Ich sehe keinen Grund, nicht initialisierte Variablen dort zu platzieren. Es ist nicht schwer, einen Speicherblock mit Null zu füllen. – supercat

+0

@supercat - Es ist nicht schwer, einen Speicherblock mit Null zu füllen. Es ist jedoch nicht notwendig, statische Variablen in die Kategorien Initialized und Uninitialized zu gliedern und ihnen separate Speicherblöcke zuzuweisen - obwohl dies auch nicht schwierig ist. –

+0

Es ist "notwendig" um Platz zu sparen, sowohl auf der Festplatte als auch im Speicher. Wenn du das "unnötig" nennst, solltest du aufhören zu programmieren ... –

1

Natürlich gibt es keine Argumente, dass es in den C-Normen ist. Erwarten Sie also, dass sich ein kompatibler Compiler so verhält.

Der technische Grund, warum es getan wurde könnte in wie der C-Startcode arbeiten verwurzelt sein. Es gibt normalerweise mehrere Speichersegmente, in die der Linker die Compilerausgabe einfügen muss, einschließlich eines Code- (Text-) Segments, eines Blockspeichersegments und eines initialisierten Variablensegments.

Nicht statische Funktionsvariablen verfügen nicht über physischen Speicher, bis der Bereich der Funktion zur Laufzeit erstellt wird, so dass der Linker nichts damit zu tun hat.

Programmcode geht natürlich in den Code (oder Text) Segment aber auch die Werte verwendet, um globale und statische Variablen zu initialisieren. Initialisierte Variablen selbst (d. H. Ihre Adressen) gehen in das initialisierte Speichersegment. Nicht initialisierte globale und statische Variablen werden in das Blockspeichersegment (bss) verschoben.

Wenn das Programm zur Ausführungszeit geladen wird, erstellt ein kleines Stück Code die C-Laufzeitumgebung. In ROM-basierten Systemen wird der Wert der initialisierten Variablen aus dem Code- (Text-) Segment in ihre jeweilige tatsächliche Adresse im RAM kopiert. Auf RAM (d.h. Platten) basierende Systeme können die Anfangswerte direkt in die endgültigen RAM-Adressen laden.

Die CRT (C Laufzeit) Nullen auch die BSS, die alle globalen und statischen Variablen enthält, die keine Initialisierer haben. Dies wurde wahrscheinlich als Vorsichtsmaßnahme gegen nicht initialisierte Daten durchgeführt. Es ist eine relativ einfache Blockfülloperation, da alle globalen und statischen Variablen zu einem Adresssegment zusammengepfercht wurden.

Natürlich schwimmt und verdoppelt kann besondere Behandlung erfordern, da ihr Wert 0.0 nicht alle Null-Bits, wenn das Floating-Format IEEE nicht 754.

Hinweis sein, dass da autovariables bei Programmladezeit nicht existieren Sie kann nicht initialisiert werden durch den Laufzeit-Startcode.

+0

Der Gleitkomma-Standard IEEE 754 wurde speziell so entworfen, dass +0 alle Null-Bits sind. Haben Sie eine Implementierung von C gesehen, die eine andere Darstellung von Gleitkommawerten verwendet, für die das nicht gilt? –

+0

@ Jeffrey: Ich habe Compiler für DSP-spezifische Float-Formate wie TI verwendet. Aber jetzt bin ich nicht 100% sicher, ob sie diese Eigenschaft auch hatten. –

+2

@ Jeffrey: Nein, das TI-Format codiert 0.0 nicht als alle Null-Bits. Es erfordert einen Exponenten von -128, um 0.0 eindeutig zu identifizieren. –

Verwandte Themen