Unter Berücksichtigung der Tatsache, dass der Speicher in vier Segmente unterteilt ist: Daten, Heap, Stack und Code, wo globale Variablen, statische Variablen, konstante Datentypen, lokale Variablen (in Funktionen definiert und deklariert), Variablen (in Hauptfunktion), Zeiger und dynamisch zugewiesener Speicherplatz (mit malloc und calloc) im Speicher gespeichert werden?
Ich denke, sie würden wie folgt vergeben:
- Globale Variablen -------> Daten
- Statische Variablen -------> Daten
- Konstante Datentypen -----> Code
- Lokale Variablen (deklariert und in Funktionen definiert) --------> Stapel
- In der Hauptfunktion deklarierte und definierte Variablen -----> Heap
- Zeiger (zum Beispiel
char *arr
,int *arr
) -------> heap - Dynamisch zugewiesener Speicherplatz (mit malloc und calloc) --------> Stapel
Ich beziehe mich nur aus der C-Perspektive auf diese Variablen.
Bitte korrigieren Sie mich, wenn ich falsch liege, da ich neu bei C bin.
c
memory
memory-management
types
starkk92
quelle
quelle
main
ist nur eine andere Funktion. Variablen werden auf den Stapel gelegt, es sei dennmalloc
, sie wären genau wie anderswo.Antworten:
Sie haben einige davon richtig verstanden, aber wer auch immer die Fragen geschrieben hat, hat Sie in mindestens einer Frage ausgetrickst:
main
Funktion ----->Heap alsoStack (der Lehrer hat versucht, Sie auszutricksen)char *arr
,int *arr
) ------->Heap- Daten oder Stapel, je nach Kontext. Mit C können Sie einen globalenstatic
Zeiger oder einen Zeiger deklarieren. In diesem Fall würde der Zeiger selbst im Datensegment landen.malloc
,calloc
,realloc
) -------->StapelheapEs ist erwähnenswert, dass "Stapel" offiziell als "automatische Speicherklasse" bezeichnet wird.
quelle
alloca
die ähnlich funktionierenmalloc
, aber die Stapelzuweisung durchführen.Für zukünftige Besucher, die sich für diese Speichersegmente interessieren, schreibe ich wichtige Punkte zu 5 Speichersegmenten in C:
Einige Köpfe hoch:
5 Speichersegmente in C:
1. Codesegment
printf("Hello, world")
dann tun , wird im Code- / Textsegment die Zeichenfolge "Hallo Welt" erstellt. Sie können dies mit demsize
Befehl unter Linux überprüfen .Datensegment
Das Datensegment ist in die folgenden zwei Teile unterteilt und liegt typischerweise unterhalb des Heap-Bereichs oder in einigen Implementierungen oberhalb des Stapels, aber das Datensegment liegt niemals zwischen dem Heap- und dem Stapelbereich.
2. Nicht initialisiertes Datensegment
int globalVar;
oder statische lokale Variablestatic int localStatic;
werden im nicht initialisierten Datensegment gespeichert.0
oderNULL
dann noch initialisieren, wird sie in ein nicht initialisiertes Datensegment oder bss verschoben.3. Initialisiertes Datensegment
int globalVar = 1;
oder statische lokale Variablestatic int localStatic = 1;
werden im initialisierten Datensegment gespeichert.4. Stapelsegment
5. Heap-Segment
malloc
,calloc
oderrealloc
Methoden.int* prt = malloc(sizeof(int) * 2)
dann beispielsweise acht Bytes im Heap zugewiesen werden und die Speicheradresse dieses Speicherorts zurückgegeben und in einerptr
Variablen gespeichert wird. Dieptr
Variable befindet sich je nach Deklaration / Verwendung entweder im Stapel oder im Datensegment.quelle
Korrigierte deine falschen Sätze
lokale konstante Variablen -----> Stapel
initialisierte globale konstante Variable -----> Datensegment
nicht initialisierte globale konstante Variable -----> bss
Variablen, die in der Hauptfunktion -----> stack deklariert und definiert sind
Zeiger (z. B. char * arr, int * arr) -------> Die Größe dieser Zeigervariablen befindet sich im Stapel.
Bedenken Sie, dass Sie den Speicher von n Bytes (mit
malloc
odercalloc
) dynamisch zuweisen und dann eine Zeigervariable erstellen, um darauf zu zeigen. Jetzt, da sichn
Speicherbytes im Heap befinden und die Zeigervariable 4 Bytes (wenn 64-Bit-Maschine 8 Bytes) benötigt, werden diese im Stapel gespeichert, um den Startzeiger dern
Bytes des Speicherblocks zu speichern .Hinweis: Zeigervariablen können auf den Speicher eines beliebigen Segments zeigen.
dynamisch zugewiesener Speicherplatz (mit malloc, calloc) --------> Heap
quelle
Eine beliebte Desktop-Architektur unterteilt den virtuellen Speicher eines Prozesses in mehrere Segmente :
Textsegment: Enthält den ausführbaren Code. Der Befehlszeiger nimmt Werte in diesem Bereich an.
Datensegment: Enthält globale Variablen (dh Objekte mit statischer Verknüpfung). Unterteilt in schreibgeschützte Daten (z. B. Zeichenfolgenkonstanten) und nicht initialisierte Daten ("BSS").
Stapelsegment: Enthält den dynamischen Speicher für das Programm, dh den freien Speicher ("Heap") und die lokalen Stapelrahmen für alle Threads. Traditionell wuchsen der C-Stapel und der C-Haufen von entgegengesetzten Enden in das Stapelsegment hinein, aber ich glaube, dass die Praxis aufgegeben wurde, weil sie zu unsicher ist.
Das AC-Programm fügt normalerweise Objekte mit statischer Speicherdauer in das Datensegment, dynamisch zugewiesene Objekte im freien Speicher und automatische Objekte im Aufrufstapel des Threads ein, in dem es sich befindet.
Auf anderen Plattformen, wie dem alten x86-Real-Modus oder auf eingebetteten Geräten, können die Dinge offensichtlich radikal anders sein.
quelle
Aus Sicht der C-Sprache kommt es nur auf Umfang, Umfang, Verknüpfung und Zugang an. Wie genau Elemente verschiedenen Speichersegmenten zugeordnet werden, hängt von der jeweiligen Implementierung ab, und das ist unterschiedlich. Der Sprachstandard spricht nicht über Speichersegmente überhaupt . Die meisten modernen Architekturen verhalten sich meist genauso. Blockbereichsvariablen und Funktionsargumente werden vom Stapel zugewiesen, Dateibereichsvariablen und statische Variablen werden von einem Daten- oder Codesegment zugewiesen, dynamischer Speicher wird von einem Heap zugewiesen, einige konstante Daten werden in schreibgeschützten Segmenten gespeichert , etc.
quelle
Eine Sache, die man bei der Speicherung beachten muss, ist die Als-ob- Regel . Der Compiler muss eine Variable nicht an einer bestimmten Stelle ablegen, sondern kann sie an einer beliebigen Stelle platzieren, solange sich das kompilierte Programm so verhält, als würde es in der abstrakten C-Maschine gemäß den Regeln der abstrakten C-Maschine ausgeführt. Dies gilt für alle Speicherdauer . Beispielsweise:
42
im generierten Assembly-Code ist, aber keine Anzeichen von404
.const
oder effektivconst
nicht befinden muss. Beispiel - Der Compiler kann diesfoo
effektiv beweisenconst
und seine Verwendung in den Code einbinden.bar
hat eine externe Verknüpfung und der Compiler kann nicht beweisen, dass er außerhalb des aktuellen Moduls nicht geändert wird, daher ist er nicht inline.malloc
muss sich nicht im Speicher befinden, der vom Heap zugewiesen wurde! Beispiel - Beachten Sie, dass der Code keinen Aufruf hatmalloc
und der Wert 42 auch nie im Speicher gespeichert ist. Er wird in einem Register gespeichert!malloc
und dessen Referenz verloren geht, ohne die Zuordnung des Objekts aufzuheben, ohnefree
dass Speicher verloren gehen muss ...malloc
muss sich untersbrk(0)
Unixen nicht innerhalb des Heaps unterhalb des Programms break ( ) befinden ...quelle
Nein, sie können sich auf dem Stapel oder im Datensegment befinden. Sie können überall zeigen.
quelle
main
und dynamisch zugewiesenen Variablen sind ebenfalls falschquelle
Minimal ausführbare Linux-Beispiele mit Disassemblierungsanalyse
Da dies ein Implementierungsdetail ist, das nicht durch Standards spezifiziert ist, schauen wir uns nur an, was der Compiler bei einer bestimmten Implementierung tut.
In dieser Antwort werde ich entweder auf bestimmte Antworten verweisen, die die Analyse durchführen, oder die Analyse direkt hier bereitstellen und alle Ergebnisse hier zusammenfassen.
Alle diese Versionen befinden sich in verschiedenen Ubuntu / GCC-Versionen, und die Ergebnisse sind wahrscheinlich über die Versionen hinweg ziemlich stabil. Wenn wir jedoch Variationen finden, geben wir genauere Versionen an.
Lokale Variable innerhalb einer Funktion
Sei es
main
oder eine andere Funktion:Wie gezeigt unter: Was bedeutet <Wert optimiert aus> in GDB?
-O0
: Stapel-O3
: registriert, wenn sie nicht verschüttet werden, sonst stapelnDie Motivation, warum der Stapel vorhanden ist, finden Sie unter: Welche Funktion haben die Push / Pop-Anweisungen, die für Register in der x86-Assembly verwendet werden?
Globale Variablen und
static
Funktionsvariablen0
oder nicht initialisiert (und daher implizit initialisiert0
):.bss
Abschnitt, siehe auch: Warum ist das .bss-Segment erforderlich?.data
Abschnittchar *
undchar c[]
Wie unter: Wo werden statische Variablen in C und C ++ gespeichert?
TODO werden auch sehr große String-Literale auf den Stapel gelegt? Oder
.data
? Oder schlägt die Kompilierung fehl?Funktionsargumente
Muss die entsprechende Aufrufkonvention durchlaufen, z. B.: Https://en.wikipedia.org/wiki/X86_calling_conventions for X86, in der entweder bestimmte Register oder Stapelpositionen für jede Variable angegeben sind.
Dann, wie unter Was bedeutet <Wert optimiert aus> in gdb? ,
-O0
Dann schlürft alles in den Stapel, während-O3
versucht Register , so viel wie möglich zu nutzen.Wenn die Funktion jedoch inline wird, werden sie wie normale Einheimische behandelt.
const
Ich glaube, dass es keinen Unterschied macht, weil Sie es wegschreiben können.
Wenn der Compiler hingegen feststellen kann, dass einige Daten niemals beschrieben werden, kann er sie theoretisch einfügen
.rodata
auch dann platzieren, wenn nicht const.TODO-Analyse.
Zeiger
Sie sind Variablen (die Adressen enthalten, die Zahlen sind), genau wie alle anderen :-)
malloc
Die Frage macht wenig Sinn für
malloc
, damalloc
es sich um eine Funktion handelt, und in:*i
ist eine Variable, die eine Adresse enthält, daher fällt sie auf den obigen Fall.Wie Malloc intern funktioniert, wenn Sie es aufrufen, markiert der Linux-Kernel bestimmte Adressen als beschreibbar in seinen internen Datenstrukturen, und wenn sie anfänglich vom Programm berührt werden, tritt ein Fehler auf und der Kernel aktiviert die Seitentabellen, die den Zugriff ermöglichen passieren ohne segfaul: Wie funktioniert x86-Paging?
Beachten Sie jedoch, dass dies im Grunde genau das ist, was der
exec
Systemaufruf unter der Haube tut, wenn Sie versuchen, eine ausführbare Datei auszuführen: Er markiert Seiten, auf die geladen werden soll, und schreibt das Programm dort. Siehe auch: Wie bringt der Kernel eine ausführbare Binärdatei zum Laufen? Linux? Abgesehen davonexec
gibt es einige zusätzliche Einschränkungen hinsichtlich des Ladeorts (z. B. ist der Code nicht verschiebbar ).Der genaue verwendete Systemaufruf
malloc
istmmap
in modernen 2020-Implementierungen enthalten und wurde in der Vergangenheitbrk
verwendet: Verwendet malloc () brk () oder mmap ()?Dynamische Bibliotheken
Grundsätzlich
mmap
in den Speicher gelangen lassen: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710Umweltvariablen und
main
'sargv
Über dem ersten Stapel: /unix/75939/where-is-the-environment-string-actual-stored TODO Warum nicht in .data?
quelle