
Benoit
In welchem Segment (.BSS, .DATA, andere) einer ausführbaren Datei werden statische Variablen gespeichert, damit sie keine Namenskollision haben? Zum Beispiel:
foo.c: bar.c:
static int foo = 1; static int foo = 10;
void fooTest() { void barTest() {
static int bar = 2; static int bar = 20;
foo++; foo++;
bar++; bar++;
printf("%d,%d", foo, bar); printf("%d, %d", foo, bar);
} }
Wenn ich beide Dateien kompiliere und sie mit einer Hauptdatei verlinke, die wiederholt fooTest() und barTest aufruft, werden die printf-Anweisungen unabhängig voneinander erhöht. Das ist sinnvoll, da die Variablen foo und bar lokal für die Übersetzungseinheit sind.
Aber wo wird der Speicher zugewiesen?
Um es klar zu sagen, die Annahme ist, dass Sie eine Toolchain haben, die eine Datei im ELF-Format ausgeben würde. Also ich glauben das da hat Platz in der ausführbaren Datei für diese statischen Variablen reserviert werden.
Nehmen wir zu Diskussionszwecken an, dass wir die GCC-Toolchain verwenden.

Don Neufeld
Wohin Ihre Statik geht, hängt davon ab, ob sie es sind Null initialisiert. Null initialisiert Statische Daten gehen ein .BSS (Block gestartet durch Symbol), nicht null initialisiert Daten gehen rein .DATEN

Karn
Wenn ein Programm in den Speicher geladen wird, ist es in verschiedene Segmente organisiert. Eines der Segmente ist DATA-Segment. Das Datensegment ist weiter in zwei Teile unterteilt:
- Initialisiertes Datensegment: Hier werden alle globalen, statischen und konstanten Daten gespeichert.
- Nicht initialisiertes Datensegment (BSS): Alle nicht initialisierten Daten werden in diesem Segment gespeichert.
Hier ist ein Diagramm, um dieses Konzept zu erklären:

Hier ist ein sehr guter Link, der diese Konzepte erklärt: Speicherverwaltung in C: Der Heap und der Stack
Tatsächlich ist eine Variable ein Tupel (Speicher, Gültigkeitsbereich, Typ, Adresse, Wert):
storage : where is it stored, for example data, stack, heap...
scope : who can see us, for example global, local...
type : what is our type, for example int, int*...
address : where are we located
value : what is our value
Lokaler Gültigkeitsbereich kann lokal für entweder die Übersetzungseinheit (Quelldatei), die Funktion oder den Block bedeuten, je nachdem, wo sie definiert ist. Um eine Variable für mehr als eine Funktion sichtbar zu machen, muss sie sich definitiv entweder im DATA- oder im BSS-Bereich befinden (je nachdem, ob sie explizit initialisiert wurde oder nicht). Es wird dann entsprechend entweder auf alle Funktionen oder Funktionen in der Quelldatei beschränkt.
Der Speicherort der Daten ist implementierungsabhängig.
Allerdings ist die Bedeutung von statisch ist “interne Verknüpfung”. Somit ist das Symbol intern zur Kompilierungseinheit (foo.c, bar.c) und kann nicht außerhalb dieser Kompilierungseinheit referenziert werden. Es kann also keine Namenskollisionen geben.

ugasoft
im Bereich “global und statisch” 🙂
In C++ gibt es mehrere Speicherbereiche:
- Haufen
- kostenlos speichern
- Stapel
- global & statisch
- konst
Sehen Hier für eine ausführliche antwort auf deine frage:
Im Folgenden werden die wichtigsten unterschiedlichen Speicherbereiche eines C++-Programms zusammengefasst. Beachten Sie, dass einige der Namen (z. B. “Haufen”) im Entwurf nicht als solche erscheinen [standard].
Memory Area Characteristics and Object Lifetimes
-------------- ------------------------------------------------
Const Data The const data area stores string literals and
other data whose values are known at compile
time. No objects of class type can exist in
this area. All data in this area is available
during the entire lifetime of the program.
Further, all of this data is read-only, and the
results of trying to modify it are undefined.
This is in part because even the underlying
storage format is subject to arbitrary
optimization by the implementation. For
example, a particular compiler may store string
literals in overlapping objects if it wants to.
Stack The stack stores automatic variables. Typically
allocation is much faster than for dynamic
storage (heap or free store) because a memory
allocation involves only pointer increment
rather than more complex management. Objects
are constructed immediately after memory is
allocated and destroyed immediately before
memory is deallocated, so there is no
opportunity for programmers to directly
manipulate allocated but uninitialized stack
space (barring willful tampering using explicit
dtors and placement new).
Free Store The free store is one of the two dynamic memory
areas, allocated/freed by new/delete. Object
lifetime can be less than the time the storage
is allocated; that is, free store objects can
have memory allocated without being immediately
initialized, and can be destroyed without the
memory being immediately deallocated. During
the period when the storage is allocated but
outside the object's lifetime, the storage may
be accessed and manipulated through a void* but
none of the proto-object's nonstatic members or
member functions may be accessed, have their
addresses taken, or be otherwise manipulated.
Heap The heap is the other dynamic memory area,
allocated/freed by malloc/free and their
variants. Note that while the default global
new and delete might be implemented in terms of
malloc and free by a particular compiler, the
heap is not the same as free store and memory
allocated in one area cannot be safely
deallocated in the other. Memory allocated from
the heap can be used for objects of class type
by placement-new construction and explicit
destruction. If so used, the notes about free
store object lifetime apply similarly here.
Global/Static Global or static variables and objects have
their storage allocated at program startup, but
may not be initialized until after the program
has begun executing. For instance, a static
variable in a function is initialized only the
first time program execution passes through its
definition. The order of initialization of
global variables across translation units is not
defined, and special care is needed to manage
dependencies between global objects (including
class statics). As always, uninitialized proto-
objects' storage may be accessed and manipulated
through a void* but no nonstatic members or
member functions may be used or referenced
outside the object's actual lifetime.
So finden Sie es selbst mit objdump -Sr
Um wirklich zu verstehen, was vor sich geht, müssen Sie die Linker-Verschiebung verstehen. Wenn Sie das noch nie berührt haben, lesen Sie zuerst diesen Beitrag.
Lassen Sie uns ein Linux x86-64 ELF-Beispiel analysieren, um es selbst zu sehen:
#include <stdio.h>
int f() {
static int i = 1;
i++;
return i;
}
int main() {
printf("%d\n", f());
printf("%d\n", f());
return 0;
}
Kompilieren mit:
gcc -ggdb -c main.c
Code dekompilieren mit:
objdump -Sr main.o
-S
dekompiliert den Code mit der ursprünglichen Quelle vermischt
-r
zeigt Umzugsinformationen
Innerhalb der Dekompilierung von f
wir sehen:
static int i = 1;
i++;
4: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # a <f+0xa>
6: R_X86_64_PC32 .data-0x4
und das .data-0x4
sagt, dass es zum ersten Byte des gehen wird .data
Segment.
Die -0x4
ist da, weil wir relative RIP-Adressierung verwenden, also die %rip
in der Anleitung u R_X86_64_PC32
.
Es ist erforderlich, weil RIP auf die zeigt folgende Anweisung, die 4 Bytes danach beginnt 00 00 00 00
was umgesiedelt wird. Ich habe dies näher erklärt unter: https://stackoverflow.com/a/30515926/895245
Wenn wir dann die Quelle ändern, um i = 1
und dieselbe Analyse durchführen, kommen wir zu folgendem Schluss:
static int i = 0
geht weiter .bss
static int i = 1
geht weiter .data
Ich glaube nicht, dass es zu einer Kollision kommt. Die Verwendung von static auf Dateiebene (außerhalb von Funktionen) markiert die Variable als lokal für die aktuelle Kompilierungseinheit (Datei). Es ist nie außerhalb der aktuellen Datei sichtbar, muss also nie einen Namen haben, der extern verwendet werden kann.
Statik verwenden Innerhalb eine Funktion ist anders – die Variable ist nur für die Funktion sichtbar (ob statisch oder nicht), es ist nur ihr Wert, der über Aufrufe dieser Funktion hinweg beibehalten wird.
Tatsächlich macht Static zwei verschiedene Dinge, je nachdem, wo es sich befindet. Im beide In einigen Fällen ist die Sichtbarkeit der Variablen jedoch so eingeschränkt, dass Sie Namensraumkollisionen beim Verlinken leicht verhindern können.
Allerdings glaube ich, dass es in der gespeichert werden würde DATA
Abschnitt, der dazu neigt, Variablen zu haben, die auf andere Werte als Null initialisiert werden. Dies ist natürlich ein Implementierungsdetail, nichts, was der Standard vorschreibt – es kümmert sich nur darum Verhalten, nicht wie die Dinge unter der Decke gemacht werden.
9970700cookie-checkWo werden statische Variablen in C und C++ gespeichert?yes
Die meisten Leute sagen Ihnen, dass sie im Abschnitt .DATA gespeichert werden sollten, anstatt Ihre Frage zu beantworten: Wo genau im Abschnitt .DATA und wie finden Sie wo. Ich sehe, Sie haben bereits eine Antwort markiert, also wissen Sie bereits, wie Sie sie finden?
– Lukmac
20. März 2011 um 20:50 Uhr
warum initialisiert und nicht initialisiert in verschiedenen Abschnitten platziert werden: linuxjournal.com/article/1059
– mhk
26. Juli 2012 um 16:39 Uhr
Der Speicherplatz, der Ihren globalen/statischen Variablen zur Laufzeit zugewiesen wird, hat nichts mit ihrer Namensauflösung zu tun, die während der Build-/Link-Zeit erfolgt. Nachdem die ausführbare Datei erstellt wurde, gibt es keine Namen mehr.
– Valdo
13. Oktober 2014 um 17:50 Uhr
Diese Frage ist bedeutungslos, da sie auf der falschen Prämisse basiert, dass “Namenskollision” von nicht exportierten Symbolen eine Sache sein kann, die existieren kann. Die Tatsache, dass es keine legitime Frage gibt, könnte erklären, wie schlimm einige der Antworten sind. Es ist schwer zu glauben, dass so wenige Leute das verstanden haben.
– Unterstrich_d
24. Juli 2016 um 22:26 Uhr