Di mana dalam memori, variabel saya disimpan di C?


156

Dengan mempertimbangkan bahwa memori dibagi menjadi empat segmen: data, heap, stack, dan kode, di mana melakukan variabel global, variabel statis, tipe data konstan, variabel lokal (didefinisikan dan dinyatakan dalam fungsi), variabel (dalam fungsi utama), pointer , dan ruang yang dialokasikan secara dinamis (menggunakan malloc dan calloc) disimpan dalam memori?

Saya pikir mereka akan dialokasikan sebagai berikut:

  • Variabel global -------> data
  • Variabel statis -------> data
  • Tipe data konstan -----> kode
  • Variabel lokal (dideklarasikan dan didefinisikan dalam fungsi) --------> stack
  • Variabel dideklarasikan dan didefinisikan dalam fungsi utama -----> heap
  • Pointer (misalnya char *arr,, int *arr) -------> heap
  • Ruang yang dialokasikan secara dinamis (menggunakan malloc dan calloc) --------> tumpukan

Saya merujuk ke variabel-variabel ini hanya dari perspektif C.

Harap perbaiki saya jika saya salah karena saya baru mengenal C.


4
Jenis tidak disimpan dalam memori.

5
mainhanyalah fungsi lain. Variabel masuk stack kecuali mallochanya seperti di tempat lain.
simonc

4
pointer (biasanya) disimpan di stack. Memori yang mereka tunjuk (biasanya dialokasikan melalui malloc / calloc) adalah (biasanya) di heap.
jpm

3
ruang yang dialokasikan secara dinamis (menggunakan malloc, calloc) --------> heap
One Man Crew

3
variabel dideklarasikan dan didefinisikan dalam fungsi utama -----> stack
One Man Crew

Jawaban:


217

Anda benar, tetapi siapa pun yang menulis pertanyaan itu menipu Anda pada setidaknya satu pertanyaan:

  • variabel global -------> data (benar)
  • variabel statis -------> data (benar)
  • tipe data konstan -----> kode dan / atau data. Pertimbangkan string literal untuk situasi ketika konstanta itu sendiri akan disimpan di segmen data, dan referensi untuk itu akan tertanam dalam kode
  • variabel lokal (dideklarasikan dan didefinisikan dalam fungsi) --------> stack (benar)
  • variabel yang dideklarasikan dan didefinisikan dalam mainfungsi -----> heap juga menumpuk (guru sedang mencoba menipu Anda)
  • pointer (ex: char *arr, int *arr) -------> tumpukan data atau stack, tergantung pada konteks. C memungkinkan Anda mendeklarasikan global atau staticpointer, dalam hal ini pointer itu sendiri akan berakhir di segmen data.
  • dialokasikan secara dinamis ruang (menggunakan malloc, calloc, realloc) --------> tumpukan tumpukan

Perlu disebutkan bahwa "tumpukan" secara resmi disebut "kelas penyimpanan otomatis".


6
Juga patut disebutkan bahwa tumpukan secara resmi tidak disebut apa-apa. Memori yang dialokasikan berasal dari suatu tempat, tidak ada nama dalam standar untuk "suatu tempat".
Steve Jessop

6
Pada beberapa sistem, (yaitu Linux dan * BSD) ada juga allocayang bekerja mirip dengan malloc, tetapi melakukan alokasi stack.
Andreas Grapentin

Kemana variabel const dideklarasikan di dalam suatu metode?
Mahori

@Ravi Tempat yang sama dengan konstanta lainnya (titik # 3 di atas).
dasblinkenlight

Saya menggunakan GCC 4.8.1 dan sepertinya tidak menyimpan variabel const lokal ke utama di segmen DATA. Di bawah ini adalah kode dan peta memori untuk 3 program tersebut: Kode 1: int main (void) {// char a [10] = "HELLO"; // 1 // const char a [10] = "HELLO"; // 2 menghasilkan 0; } PETA MEMORI UNTUK DI ATAS: data teks bss dec hex nama file 7264 1688 1040 9992 2708 a.exe PETA MEMORI UNTUK 2: data teks bss dec hex nama file 7280 1688 1040 10008 2718 a.exe MEMORY MAP FOR 3: data teks bss dec hex nama file 7280 1688 1040 10008 2718 a.exe
Mahori

124

Bagi pengunjung masa depan yang mungkin tertarik mengetahui tentang segmen memori tersebut, saya menulis poin penting tentang 5 segmen memori di C:

Beberapa kepala:

  1. Setiap kali program C dijalankan, sebagian memori dialokasikan dalam RAM untuk eksekusi program. Memori ini digunakan untuk menyimpan kode yang sering dieksekusi (data biner), variabel program, dll. Segmen memori di bawah ini berbicara tentang hal yang sama:
  2. Biasanya ada tiga jenis variabel:
    • Variabel lokal (juga disebut sebagai variabel otomatis dalam C)
    • Variabel global
    • Variabel statis
    • Anda dapat memiliki variabel statis global atau statis lokal, tetapi ketiga di atas adalah tipe induk.

5 Segmen Memori dalam C:

1. Segmen Kode

  • Segmen kode, juga disebut sebagai segmen teks, adalah area memori yang berisi kode yang sering dieksekusi.
  • Segmen kode sering hanya-baca untuk menghindari risiko ditimpa oleh bug pemrograman seperti buffer-overflow, dll.
  • Segmen kode tidak mengandung variabel program seperti variabel lokal ( juga disebut sebagai variabel otomatis dalam C ), variabel global, dll.
  • Berdasarkan implementasi C, segmen kode juga dapat berisi string literal baca-saja. Misalnya, ketika Anda melakukannya printf("Hello, world")maka string "Halo, dunia" akan dibuat di segmen kode / teks. Anda dapat memverifikasi ini menggunakan sizeperintah di OS Linux.
  • Bacaan lebih lanjut

Segmen Data

Segmen data dibagi dalam dua bagian di bawah ini dan biasanya terletak di bawah area tumpukan atau dalam beberapa implementasi di atas tumpukan, tetapi segmen data tidak pernah terletak di antara area tumpukan dan tumpukan.

2. Segmen data yang tidak diinisialisasi

  • Segmen ini juga dikenal sebagai bss .
  • Ini adalah bagian dari memori yang berisi:
    1. Variabel global tidak diinisialisasi (termasuk variabel pointer)
    2. Variabel global konstan yang tidak diinisialisasi .
    3. Variabel statis lokal tidak diinisialisasi .
  • Setiap variabel lokal global atau statis yang tidak diinisialisasi akan disimpan di segmen data yang tidak diinisialisasi
  • Misalnya: variabel global int globalVar;atau variabel lokal statis static int localStatic;akan disimpan di segmen data yang tidak diinisialisasi.
  • Jika Anda mendeklarasikan variabel global dan menginisialisasi sebagai 0atau NULLmasih tetap akan pergi ke segmen data yang tidak diinisialisasi atau bss.
  • Bacaan lebih lanjut

3. Segmen data yang diinisialisasi

  • Segmen ini menyimpan:
    1. Variabel global yang diinisialisasi (termasuk variabel pointer)
    2. Variabel global konstan yang diinisialisasi .
    3. Variabel statis lokal diinisialisasi .
  • Misalnya: variabel global int globalVar = 1;atau variabel lokal statis static int localStatic = 1;akan disimpan di segmen data yang diinisialisasi.
  • Segmen ini selanjutnya dapat diklasifikasikan ke dalam area read-only yang diinisialisasi dan area read-write yang diinisialisasi . Variabel global konstan yang diinisialisasi akan masuk ke area read-only yang diinisialisasi sementara variabel yang nilainya dapat dimodifikasi saat runtime akan masuk ke area read-write yang diinisialisasi .
  • Ukuran segmen ini ditentukan oleh ukuran nilai dalam kode sumber program, dan tidak berubah pada saat dijalankan .
  • Bacaan lebih lanjut

4. Segmen Stack

  • Stack segment digunakan untuk menyimpan variabel yang dibuat di dalam fungsi ( fungsi bisa berupa fungsi utama atau fungsi yang ditentukan pengguna ), seperti variabel
    1. Variabel lokal dari fungsi (termasuk variabel pointer)
    2. Argumen diteruskan ke fungsi
    3. Alamat pengembalian
  • Variabel yang disimpan dalam tumpukan akan dihapus segera setelah eksekusi fungsi selesai.
  • Bacaan lebih lanjut

5. Segmen Heap

  • Segmen ini untuk mendukung alokasi memori dinamis. Jika programmer ingin mengalokasikan beberapa memori dinamis maka di C itu dilakukan dengan menggunakan malloc, callocatau reallocmetode.
  • Misalnya, ketika int* prt = malloc(sizeof(int) * 2)delapan byte akan dialokasikan di heap dan alamat memori lokasi itu akan dikembalikan dan disimpan dalam ptrvariabel. The ptrvariabel akan baik pada tumpukan atau data segmen tergantung pada cara dinyatakan / digunakan.
  • Bacaan lebih lanjut

Bukankah itu seharusnya diinisialisasi daripada diinisialisasi dalam 3. Segmen data yang diinisialisasi.
Suraj Jain

Re "disimpan dalam segmen data yang tidak diinisialisasi" (beberapa contoh): Apakah maksud Anda "disimpan tidak diinisialisasi dalam segmen data" ?
Peter Mortensen

@ PeterMensensen maksud saya kedua hal. "Setiap variabel lokal global atau statis yang tidak diinisialisasi akan disimpan dalam segmen data yang tidak diinisialisasi"
hagrawal

bagaimana kita bisa memiliki variabel statis global dalam C?

di bawah "beberapa kepala", saya menemukan titik ini "Anda dapat memiliki variabel statis global atau statis lokal, tetapi tiga di atas adalah tipe induk." di mana Anda merujuk pada istilah "global static". Maksud saya adalah variabel statis tidak boleh global. yaitu, jika ada variabel yang harus bersifat global maka itu harus dapat diakses sampai pelaksanaan program selesai. Tolong jelaskan dan bantu jika saya salah.

11

Koreksi kalimat salah Anda

constant data types ----->  code //wrong

variabel konstan lokal -----> stack

variabel konstan global yang diinisialisasi -----> segmen data

variabel konstan global tidak diinisialisasi -----> bss

variables declared and defined in main function  ----->  heap //wrong

variabel dideklarasikan dan didefinisikan dalam fungsi utama -----> stack

pointers(ex:char *arr,int *arr) ------->  heap //wrong

dynamically allocated space(using malloc,calloc) --------> stack //wrong

pointer (mis: char * arr, int * arr) -------> ukuran variabel pointer akan berada di stack.

Pertimbangkan bahwa Anda mengalokasikan memori n byte (menggunakan mallocatau calloc) secara dinamis dan kemudian membuat variabel pointer untuk mengarahkannya. Sekarang nbyte memori berada di heap dan variabel pointer memerlukan 4 byte (jika mesin 64 bit 8 byte) yang akan di stack untuk menyimpan pointer mulai dari nbyte byte memori.

Catatan: Variabel pointer dapat menunjukkan memori segmen apa pun.

int x = 10;
void func()
{
int a = 0;
int *p = &a: //Now its pointing the memory of stack
int *p2 = &x; //Now its pointing the memory of data segment
chat *name = "ashok" //Now its pointing the constant string literal 
                     //which is actually present in text segment.
char *name2 = malloc(10); //Now its pointing memory in heap
...
}

ruang yang dialokasikan secara dinamis (menggunakan malloc, calloc) --------> heap


pointer dapat berada di tumpukan atau tumpukan (lihat khususnya: pointer ke pointer)
argentage

@airza: Sekarang diperbarui. Sebenarnya saya memperbarui rincian itu saja :)
rashok

Di peta memori berikut, bisakah Anda menunjukkan di mana tumpukan dan tumpukan? Saya tidak yakin apakah ini pertanyaan yang benar karena tumpukan dan memori hanya berlaku pada saat dijalankan. PETA MEMORY: "data teks bss dec hex nama file 7280 1688 1040 10008 2718 a.exe"
Mahori

7

Arsitektur desktop yang populer membagi memori virtual suatu proses dalam beberapa segmen :

  • Segmen teks: berisi kode yang dapat dieksekusi. Penunjuk instruksi mengambil nilai dalam rentang ini.

  • Segmen data: berisi variabel global (yaitu objek dengan tautan statis). Dibagi dalam data read-only (seperti konstanta string) dan data yang tidak diinisialisasi ("BSS").

  • Segmen tumpukan: berisi memori dinamis untuk program, yaitu toko bebas ("tumpukan") dan bingkai tumpukan lokal untuk semua utas. Secara tradisional tumpukan C dan tumpukan C dulu tumbuh ke segmen tumpukan dari ujung yang berlawanan, tapi saya percaya bahwa praktik telah ditinggalkan karena terlalu tidak aman.

Program AC biasanya menempatkan objek dengan durasi penyimpanan statis ke dalam segmen data, objek yang dialokasikan secara dinamis di toko bebas, dan objek otomatis pada tumpukan panggilan dari utas tempat ia tinggal.

Pada platform lain, seperti mode real x86 lama atau pada perangkat yang disematkan, segalanya dapat sangat berbeda.


"Saya percaya bahwa praktik telah ditinggalkan karena terlalu tidak aman" - dan membuatnya tidak mungkin untuk mengimplementasikan utas, sejak saat itu Anda memerlukan lebih dari satu tumpukan per program dan semuanya tidak dapat pada akhirnya :-)
Steve Jessop

@SteveJessop: Ya, saya juga memikirkan itu. Tapi utas sudah ada sejak lama - saya tidak tahu apakah semua tumpukan benang juga tumbuh mundur, atau apakah mereka tumbuh seperti tumpukan ... lagi pula, saat ini semuanya berjalan ke arah yang sama dan ada penjaga halaman.
Kerrek SB

6

Saya merujuk ke variabel-variabel ini hanya dari perspektif C.

Dari perspektif bahasa C , yang penting adalah luas, cakupan, keterkaitan, dan akses; persis bagaimana item dipetakan ke segmen memori yang berbeda hingga implementasi individu, dan itu akan bervariasi. Standar bahasa tidak berbicara tentang segmen memori sama sekali . Kebanyakan arsitektur modern kebanyakan bertindak dengan cara yang sama; variabel blok ruang lingkup dan argumen fungsi akan dialokasikan dari tumpukan, ruang lingkup file dan variabel statis akan dialokasikan dari segmen data atau kode, memori dinamis akan dialokasikan dari tumpukan, beberapa data konstan akan disimpan dalam segmen hanya-baca , dll.


3

Satu hal salah satu kebutuhan yang perlu diingat tentang penyimpanan adalah sebagai-jika aturan . Kompiler tidak diharuskan untuk meletakkan variabel di tempat tertentu - melainkan dapat menempatkannya di tempat yang diinginkan selama program yang dikompilasi berperilaku seolah-olah dijalankan di mesin C abstrak sesuai dengan aturan mesin C abstrak. Ini berlaku untuk semua durasi penyimpanan . Sebagai contoh:

  • variabel yang tidak diakses semua dapat dihilangkan sepenuhnya - ia tidak memiliki penyimpanan ... di mana saja. Contoh - lihat bagaimana ada 42dalam kode perakitan yang dihasilkan tetapi tidak ada tanda 404.
  • variabel dengan durasi penyimpanan otomatis yang tidak diambil alamatnya tidak perlu disimpan dalam memori sama sekali. Contohnya adalah variabel loop.
  • variabel yang constatau secara efektif consttidak perlu berada dalam memori. Contoh - kompiler dapat membuktikan bahwa foosecara efektif constdan inline penggunaannya ke dalam kode. barmemiliki tautan eksternal dan kompiler tidak dapat membuktikan bahwa itu tidak akan diubah di luar modul saat ini, oleh karena itu tidak diuraikan.
  • objek yang dialokasikan dengan malloctidak perlu berada dalam memori yang dialokasikan dari tumpukan! Contoh - perhatikan bagaimana kode tidak memiliki panggilan ke mallocdan nilai 42 tidak pernah disimpan dalam memori, ia disimpan dalam register!
  • dengan demikian objek yang telah dialokasikan oleh mallocdan referensi hilang tanpa deallocating objek dengan free tidak perlu membocorkan memori ...
  • objek yang dialokasikan oleh malloctidak perlu berada di dalam tumpukan di bawah program break ( sbrk(0)) pada Unixen ...

1

pointer (mis: char * arr, int * arr) -------> heap

Tidak, mereka bisa di stack atau di segmen data. Mereka dapat menunjuk ke mana saja.


Pernyataan tentang maindan variabel yang dialokasikan secara dinamis juga salah
simonc

Tidak hanya di stack atau segmen data. Pikirkan pointer yang menunjuk ke array pointer. Dalam hal ini pointer dalam array disimpan di heap.
Sebi2020

1
  • Variabel / variabel otomatis ---> bagian stack
  • Variabel yang dialokasikan secara dinamis ---> bagian heap
  • Variabel global yang diinisialisasi -> bagian data
  • Variabel global tidak diinisialisasi -> bagian data (bss)
  • Variabel statis -> bagian data
  • Konstanta string -> bagian teks / bagian kode
  • Fungsi -> bagian teks / bagian kode
  • Kode teks -> bagian teks / bagian kode
  • Register -> register CPU
  • Input baris perintah -> bagian lingkungan / baris perintah
  • Variabel lingkungan -> bagian lingkungan / baris perintah

Apa yang dimaksud dengan bagian lingkungan / baris perintah? Apakah mereka ada di Linux?
Haoyuan Ge

-1

Linux contoh runnable minimal dengan analisis pembongkaran

Karena ini adalah detail implementasi yang tidak ditentukan oleh standar, mari kita lihat apa yang dilakukan kompiler pada implementasi tertentu.

Dalam jawaban ini, saya akan menautkan ke jawaban spesifik yang melakukan analisis, atau memberikan analisis langsung di sini, dan merangkum semua hasil di sini.

Semua itu ada dalam berbagai versi Ubuntu / GCC, dan hasilnya mungkin cukup stabil di seluruh versi, tetapi jika kita menemukan variasi mari kita tentukan versi yang lebih tepat.

Variabel lokal di dalam suatu fungsi

Baik itu mainatau fungsi lainnya:

void f(void) {
    int my_local_var;
}

Seperti yang ditunjukkan di: Apa yang dimaksud dengan <value dioptimalkan keluar> di gdb?

  • -O0: tumpukan
  • -O3: register jika tidak tumpah, tumpuk sebaliknya

Untuk motivasi mengapa tumpukan ada, lihat: Apa fungsi instruksi push / pop yang digunakan pada register dalam rakitan x86?

Variabel global dan staticvariabel fungsi

/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;

/* DATA */
int my_global_implicit_explicit_1 = 1;

void f(void) {
    /* BSS */
    static int my_static_local_var_implicit;
    static int my_static_local_var_explicit_0 = 0;

    /* DATA */
    static int my_static_local_var_explicit_1 = 1;
}
  • jika diinisialisasi 0atau tidak diinisialisasi (dan karena itu secara implisit diinisialisasi ke 0): .bssbagian, lihat juga: Mengapa segmen .bss diperlukan?
  • jika tidak: .databagian

char * dan char c[]

Seperti yang ditunjukkan pada: Di mana variabel statis disimpan dalam C dan C ++?

void f(void) {
    /* RODATA / TEXT */
    char *a = "abc";

    /* Stack. */
    char b[] = "abc";
    char c[] = {'a', 'b', 'c', '\0'};
}

TODO akankah string string yang sangat besar juga diletakkan di tumpukan? Atau .data? Atau apakah kompilasi gagal?

Argumen fungsi

void f(int i, int j);

Harus melalui konvensi pemanggilan yang relevan, misalnya: https://en.wikipedia.org/wiki/X86_calling_conventions untuk X86, yang menentukan register spesifik atau lokasi stack untuk setiap variabel.

Lalu seperti yang ditunjukkan pada Apa yang dimaksud dengan <value dioptimalkan keluar> di gdb? , -O0kemudian mencelupkan semuanya ke tumpukan, sambil -O3mencoba menggunakan register sebanyak mungkin.

Namun, jika fungsinya digarisbawahi, mereka diperlakukan seperti penduduk lokal biasa.

const

Saya percaya bahwa tidak ada bedanya karena Anda dapat mengetikkannya.

Sebaliknya, jika kompiler dapat menentukan bahwa beberapa data tidak pernah ditulis, maka secara teori dapat menempatkannya .rodatabahkan jika bukan const.

Analisis TODO.

Pointer

Mereka adalah variabel (yang berisi alamat, yang merupakan angka), jadi sama dengan yang lainnya :-)

malloc

Pertanyaannya tidak masuk akal malloc, karena mallocmerupakan fungsi, dan dalam:

int *i = malloc(sizeof(int));

*i adalah variabel yang berisi alamat, jadi itu jatuh pada kasus di atas.

Adapun bagaimana malloc bekerja secara internal, ketika Anda menyebutnya kernel Linux menandai alamat tertentu sebagai dapat ditulis pada struktur data internal, dan ketika mereka disentuh oleh program pada awalnya, kesalahan terjadi dan kernel mengaktifkan tabel halaman, yang memungkinkan akses terjadi tanpa segfaul: Bagaimana cara kerja paging x86?

Namun perlu dicatat bahwa ini pada dasarnya persis seperti yang dilakukan execsyscall di bawah tenda ketika Anda mencoba menjalankan executable: ia menandai halaman yang ingin di-load, dan menulis program di sana, lihat juga: Bagaimana kernel mendapatkan file biner yang dapat dieksekusi berjalan di bawah linux? Kecuali itu execmemiliki beberapa batasan tambahan di mana memuat (misalnya kode tidak dapat dipindahkan ).

Syscall yang tepat digunakan untuk mallocadalah mmapdi yang modern 2020 implementasi, dan di masa lalu brkdigunakan: Apakah malloc () digunakan York () atau mmap ()?

Perpustakaan dinamis

Pada dasarnya mmaped ke memori: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

variabel envinroment dan main'sargv

Di atas tumpukan awal: /unix/75939/where-is-the-environment-string-actual-stored TODO mengapa tidak di. Data?

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.