Warum Dateibereich statische Variablen müssen initialisiert werden?

7

C ++ Standardinitialisierung löscht nicht Variablen mit automatischem Speicher, warum die spezielle Behandlung für statische Speichervariablen?

War es etwas, das von C und C ++ definiert wurde, mit dem es kompatibel sein muss? Wenn das der Fall ist, entscheidet C, Null-Initialisierung zu tun?

Wenn ein Dateibereich statische Variablen mit einem Initialisierer versehen wird, werden sie zuerst initialisiert und dann wieder konstant / dynamisch initialisiert. Ist das nicht überflüssig? Der folgende Code stammt beispielsweise aus cppreference: Ссылка

%Vor%

In diesem Fall kann n nicht direkt mit argc initialisiert werden?

BEARBEITEN: Ein Teil dieser Frage wurde durch die folgende Frage beantwortet: Statische Variableninitialisierung? Aber ich glaube nicht, dass es ein Duplikat ist, weil die Antworten in der anderen Frage meine zweite Frage nicht beantwortet haben, dh. warum die 2-stufige Initialisierung. Außerdem sagt der Titel des anderen Beitrags nicht wirklich, was genau die Frage ist.

    
swang 09.09.2014, 10:56
quelle

3 Antworten

12

Das Verhalten auf den Betriebssystemen, auf denen C entwickelt wurde, hat diese Standardbestimmungen geprägt. Wenn Anwendungen geladen werden, stellt der OS Loader Speicherplatz für das BSS bereit. Es ist wünschenswert, dass es auf Nullen zurückgesetzt wird. Wenn ein anderer Prozess diesen Speicher früher verwendet hat, könnte das Programm, das Sie starten, den Speicherinhalt des vorherigen Prozesses durchsuchen und möglicherweise Passwörter, Konversationen oder andere Daten sehen. Nicht jedes frühe oder einfache Betriebssystem kümmert sich darum, aber die meisten tun es, also ist die Initialisierung meistens "frei", da es eine Aufgabe ist, die das Betriebssystem ohnehin tun wird.

Wenn diese Voreinstellung 0 ist, kann die Implementierung leicht auf Flags verweisen, die während der dynamischen Initialisierung gesetzt wurden, da es kein nicht initialisiertes Speicherlesen und folglich undefiniertes Verhalten geben wird. Zum Beispiel, gegeben ...

%Vor%

... der Compiler / die Implementierung kann implizit auch etwas wie eine Variable static bool __f_statics_initialised hinzufügen - was "glücklicherweise" aufgrund des Nullsetzungsverhaltens standardmäßig 0 / false ist - zusammen mit dem Initialisierungscode ähnlich wie (möglicherweise) Thread-sichere Version von) ...

%Vor%

Für das obige Szenario wird die Initialisierung beim ersten Aufruf durchgeführt, aber für globale Variablen erfolgt dies in einer nicht spezifizierten pro-Objekt-Reihenfolge, manchmal bevor main() aufgerufen wird. Wenn ein objektindividueller Initialisierungscode und eine dynamische Initialisierung erforderlich sind, um Statik im nicht initialisierten Zustand von den bekannten unterscheiden zu können, ist es in diesem Szenario einfacher, robusten Startcode zu schreiben. Zum Beispiel können Funktionen prüfen, ob ein nicht-lokaler statischer Zeiger immer noch 0 ist, und new ein Objekt dafür, falls ja.

Es ist auch bemerkenswert, dass viele CPUs sehr effiziente Anweisungen haben, um große Speicherbereiche auf Null zu setzen.

    
Tony Delroy 09.09.2014, 11:11
quelle
7

Zero-Initialisierung von Globals kommt "kostenlos", weil der Speicher für sie im Segment "BSS" vor dem Start von main () zugewiesen wird. Das heißt, wenn Sie auf Ihren Zeiger p zugreifen, muss der Zeiger selbst irgendwo gespeichert werden, und das ist irgendwo ein bestimmter Teil der Bits in BSS. Da es zu etwas initialisiert werden muss, warum nicht null?

Nun, warum tun dies nicht automatische / stack-Variablen? Weil das Zeit kosten würde: Die Zuweisung auf dem Stapel ist nichts anderes als den Stapelzeiger zu erhöhen (oder zu dekrementieren, eine Frage der Perspektive). Welcher Müll dort auch war, kann dort gelassen werden (gemäß C). Da wir null-init nicht kostenlos erhalten können, bekommen wir es überhaupt nicht (weil es wieder C ist, wo wir nicht gerne für Dinge bezahlen, die wir nicht benutzen).

Default-Initialisierung eines std :: string oder anderen Klassen-Typ ist ein bisschen komplexer: C ++ erfordert, dass es irgendwie initialisiert wird, und der Standard-Konstruktor ist natürlich derjenige, der verwendet wird, und ja, technisch ist es Null- initialisiert zuerst, aber wie besprochen, dass Zero-Init "kostenlos" passiert ist. Es könnte für eine Implementierung zulässig sein, die std :: string ausreichend analysieren kann, um zur Build-Zeit zu bestimmen, wie ihre Bits initialisiert werden, als ob der Standardkonstruktor aufgerufen würde, aber ich weiß nicht, ob eine Implementierung das tut.

    
John Zwinck 09.09.2014 11:01
quelle
3

Globale und statische Variablen in C haben während der Laufzeit des Programms eine feste Speicheradresse. Dies ermöglicht dem Programm-Launcher, sie zu initialisieren, indem ein geeigneter Speicherbereich aus der ausführbaren Datei in den Computerspeicher kopiert wird.

Als Konsequenz kann (muss) C für jede statische / globale Variable einen Anfangswert liefern. Wenn der Benutzer keinen Wert angibt, wird standardmäßig 0 verwendet. Im Gegensatz zur lokalen Variablen erhöht dies weder den Speicher noch die Geschwindigkeit der Anwendung (da ein Wert trotzdem geschrieben werden muss).

Möglicherweise kann dieses Verhalten (Kopieren statischer Anfangsdaten in ausführbare Dateien) sehr schlecht sein, wenn Sie große Arrays ohne Anfangsdaten haben. Tatsächlich scheint es, dass moderne C-Compiler in der Lage sind, diese Verschwendung zu vermeiden, und werden große Arrays mit Nullen auffüllen, anstatt Nullen im Programm zu speichern. Wenn die Regel jedoch einmal vorliegt, sind sie gezwungen, die Region zu füllen, auch wenn der Benutzer sie möglicherweise nicht benötigt. Wie auch immer, dies ist eine sehr billige Operation, die einmal beim Programmstart durchgeführt wird.

    
Emanuele Paolini 09.09.2014 11:02
quelle

Tags und Links