Mengapa buku mengatakan, "kompiler mengalokasikan ruang untuk variabel dalam memori"?

18

Mengapa buku mengatakan, "kompiler mengalokasikan ruang untuk variabel dalam memori". Bukankah itu executable yang melakukan itu? Maksud saya, misalnya, jika saya menulis program berikut,

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

dan kompilasi, dan dapatkan executable (biarkan program.exe), sekarang, jika saya menjalankan program.exe, file yang dapat dieksekusi ini sendiri akan memerintahkan untuk mengalokasikan beberapa ruang untuk variabel foo. Bukan? Tolong jelaskan mengapa buku terus berkata, "kompiler akan melakukan ini ... lakukan itu".

The Peaceful Coder
sumber
11
buku mana yang kamu bicarakan?
wirrbel
4
"Pertanyaan terkait" Anda harus menjadi pertanyaan terpisah.
SShaheen
The sizeofPertanyaan sekarang terletak di Mengapa sizeof disebut operator saat kompilasi?
Compiler menghasilkan kode yang melakukan ini atau itu yang mereka katakan. langsung atau tidak langsung.
old_timer
FYI stackoverflow.com/questions/7372024/... dan perhatikan bahwa kompiler dapat memutuskan untuk mengubah lokasi variabel yang dirasakan dalam memori demi penyelarasan misalnya: stackoverflow.com/questions/17774276/…
NoChance

Jawaban:

20

Anda benar bahwa kompiler seperti itu hilang ketika program Anda benar-benar berjalan. Dan jika itu berjalan pada mesin yang berbeda, kompiler bahkan tidak tersedia lagi.

Saya kira ini untuk membuat perbedaan yang jelas antara memori yang sebenarnya dialokasikan oleh kode Anda sendiri. Kompiler akan memasukkan beberapa kode dalam program Anda yang melakukan alokasi memori (seperti menggunakan perintah baru, malloc atau serupa).

Jadi buku menggunakan "kompiler melakukan ini atau itu" sering mengatakan kompiler menambahkan beberapa kode yang tidak secara eksplisit disebutkan dalam file kode Anda. Cukup benar bahwa ini tidak persis apa yang terjadi. Dari sudut pandang ini banyak hal yang disebutkan dalam tutorial akan salah tetapi akan membutuhkan penjelasan yang agak rumit.

thorsten müller
sumber
Ya, itulah yang saya yakini. Terima kasih atas jawaban cepatnya!
The Peaceful Coder
12
kompiler mengalokasikan untuk variabel foo pada stack dengan menggantinya dengan offset ke stack pointer selama kompilasi. Sama sekali tidak terkait dengan alokasi tumpukan yang dilakukan oleh mallocet. Al.
wirrbel
@holger: Keberatan Anda tentu saja benar secara teknis. Tetapi ruang stack seperti itu masih harus dialokasikan ketika program dimulai sebelum dapat digunakan (yang dapat terjadi dalam berbagai cara, kadang-kadang tergantung pada arsitektur CPU). Saya mencoba menemukan beberapa detail bagaimana ini terjadi tetapi tidak berhasil.
thorsten müller
2
Saya pikir ukuran tumpukan untuk utas utama dicadangkan oleh linker dan kemudian ditangani oleh OS. Untuk utas khusus, ini lebih mirip dengan alokasi tumpukan yaitu pemanggil dapat memperbaiki ukuran saat runtime.
wirrbel
4

Itu tergantung pada variabelnya. OS mengalokasikan heap, program akan mengalokasikan stack dan kompiler akan mengalokasikan ruang untuk global / statika, yaitu mereka dibangun ke dalam exe itu sendiri. Jika Anda mengalokasikan 1MB memori global, ukuran exe Anda akan meningkat setidaknya 1MB

James
sumber
1
Bukan itu pertanyaannya.
Philipp
2
sebenarnya itu lebih dekat ke pertanyaan daripada jawaban lain yang tercantum di sini.
wirrbel
@ James Ah, ini bukan pengalaman saya. Sebagai contoh, int test[256][1024]; int main(){ test[0][0]=2; return 0; } program kecil ini memiliki 1MB dialokasikan tetapi hanya menghasilkan saya file objek 1,4 Kb dan 8,4 Kb dieksekusi. Ini harus menggunakan jumlah RAM yang benar.
Garet Claborn
1
Bukankah seharusnya hanya perintah alokasi yang disimpan untuk global? Jika Anda memiliki hardcoded semua nilai menggunakan primitif seperti int atau char, ukuran executable pasti akan meningkat lebih dari jumlah variabel yang ditambahkan. Seperti int a1=1,a2=2,... semua jalan ke ... , a1048576=1048576;Hanya dengan begitu Anda pasti akan mendapatkan sesuatu yang lebih besar dari 1mb saya pikir.
Garet Claborn
2
Apa pun yang memasukkan data ke bagian BSS dari exe
James
4

apa kompilernya akan dilakukan adalah mengambil kode Anda dan mengkompilasinya ke dalam kode mesin. Apa yang Anda sebutkan adalah contoh yang baik di mana kompiler hanya perlu menerjemahkan.

Misalnya, ketika Anda menulis

int foo;

Anda dapat melihat bahwa sebagai 'Saya memberi tahu kompiler untuk [ dalam output yang dihasilkannya ] meminta agar komputer mencadangkan ram yang cukup untuk int yang dapat saya referensi nanti. Kompiler mungkin akan menggunakan id sumber daya atau mekanisme untuk melacak foo di kode mesin, Anda bisa menggunakan foo dalam file teks alih-alih menulis perakitan!Hore !

Jadi Anda mungkin juga melihat ini karena kompiler sedang menulis surat ( atau mungkin novel / ensiklopedia ) untuk semua prosesor dan perangkat yang ditargetkan. Surat itu ditulis dalam sinyal biner yang (umumnya) dapat diterjemahkan ke prosesor yang berbeda dengan mengubah target. 'Huruf' dan / atau kombo apa pun dapat mengirimkan segala jenis permintaan dan / atau data - seperti tolong alokasikan ruang untuk variabel ini yang digunakan oleh programmer.

Garet Claborn
sumber
3

Mengatakan "kompiler mengalokasikan memori" mungkin secara faktual tidak akurat dalam arti literal, tetapi itu adalah metafora yang sugestif dengan cara yang benar.

Apa yang sebenarnya terjadi adalah bahwa kompiler membuat program yang mengalokasikan memori sendiri. Kecuali itu bukan program yang mengalokasikan memori, tetapi OS.

Jadi apa yang sebenarnya terjadi adalah bahwa kompiler membuat program yang menggambarkan persyaratan memorinya dan OS mengambil deskripsi itu dan menggunakannya untuk mengalokasikan memori. Kecuali bahwa OS adalah sebuah program, dan program tidak benar-benar melakukan apa-apa, mereka menggambarkan perhitungan yang dilakukan oleh CPU. Kecuali bahwa CPU benar-benar hanya sirkuit elektronik yang rumit, bukan homonculus kecil yang antropomorfis.

Tetapi masuk akal untuk berpikir tentang program dan kompiler dan CPU sebagai orang kecil yang hidup di dalam komputer, bukan karena mereka sebenarnya, tetapi karena itu adalah metafora yang cocok dengan otak manusia dengan baik.

Beberapa metafora bekerja dengan baik untuk menggambarkan hal-hal pada satu tingkat abstraksi, tetapi tidak berfungsi dengan baik pada tingkat lain. Jika Anda berpikir pada tingkat kompiler, masuk akal untuk menggambarkan tindakan menghasilkan kode yang akan mengakibatkan memori dialokasikan ketika program yang sedang dikompilasi sebenarnya dijalankan sebagai "mengalokasikan memori". Cukup dekat sehingga ketika kita berpikir tentang cara kerja kompiler, kita punya ide yang tepat, dan tidak terlalu bertele-tele sehingga kita lupa apa yang kita lakukan. Jika kami mencoba menggunakan metafora itu pada tingkat program yang dikompilasi berjalan, itu menyesatkan dengan cara yang aneh, yang Anda perhatikan.

Michael Shaw
sumber
0

Itu kompiler yang memutuskan di mana menyimpan variabel - bisa di stack atau register gratis. Apa pun keputusan penyimpanan yang dibuat oleh kompiler, kode mesin yang sesuai untuk mengakses variabel tersebut akan dihasilkan dan tidak dapat diubah dalam waktu berjalan. Dalam hal ini, kompiler bertugas mengalokasikan ruang untuk variabel dan program.exe akhir hanya bertindak secara membabi buta seperti zombie dalam waktu berjalan.

Sekarang, jangan bingung dengan manajemen memori dinamis yang berbeda seperti malloc, baru atau mungkin manajemen memori Anda sendiri. Kompiler berurusan dengan penyimpanan variabel dan akses tetapi tidak peduli apa arti nilai aktual dalam kerangka / pustaka lain. Sebagai contoh:

byte* pointer = (byte*)malloc(...);

Dalam menjalankan waktu, malloc dapat mengembalikan nomor sewenang-wenang tetapi kompiler tidak peduli, yang penting adalah di mana menyimpan nomor itu.

Codism
sumber
0

Ungkapan yang lebih akurat adalah: - "kompiler memberitahu loader untuk memesan ruang untuk variabel"

Dalam lingkungan C-ish akan ada tiga jenis ruang untuk variabel: -

  • blok tetap untuk variabel statis
  • Blok besar untuk variabel "otomatis" biasanya disebut sebagai "tumpukan". Fungsi ambil sepotong saat masuk dan lepaskan saat kembali.
  • Blok besar yang disebut "heap" yang merupakan tempat memori yang dikelola program dialokasikan dari (menggunakan malloc () atau API manajemen memori serupa.

Pada memori tumpukan OS modern tidak akan benar-benar dicadangkan tetapi dialokasikan sesuai kebutuhan.

James Anderson
sumber
0

Ya, Anda benar, dalam hal ini (mendeklarasikan variabel dalam suatu fungsi), kalimat buku Anda mungkin salah: ketika Anda mendeklarasikan variabel dalam suatu fungsi, itu akan dialokasikan pada tumpukan saat memasuki fungsi. Bagaimanapun, kompiler harus mengoptimalkan situasi: jika fungsinya non-rekursif ( main()adalah kandidat yang baik untuk itu), tidak apa-apa untuk "mengalokasikan" itu waktu kompilasi (pada BSS).

(Jika Anda ingin tahu di mana variabel Anda berada, Anda dapat memeriksanya dengan cara yang kotor (jika Anda tidak ingin memeriksa struktur file obj, mengapa tidak?), Sehingga Anda dapat mendeklarasikan beberapa jenis variabel yang berbeda: konstan, statis, dinamis, malloc()-terokasi dll, dan menampilkan alamatnya (gunakan %Xformatter printf()untuk keterbacaan yang lebih baik). Variabel yang berada di tumpukan akan memiliki alamat memori yang sangat berbeda.)

ern0
sumber
0

Satu-satunya hal yang dilakukan pada saat runtime adalah menabrak tumpukan poinbter dengan jumlah tertentu. Jadi kompilator memutuskan sebelumnya:

  • berapa banyak ruang stack yang dibutuhkan untuk fungsi ini.
  • Apa yang diimbangi dari stack pointer setiap variabel individual akan ditemukan.

Yang ini bisa disebut "alokasi", tetapi tentu saja, selama waktu kompilasi, ia hanya mengambil tempat dalam model yang dimiliki oleh kompiler dari program yang sedang berjalan.

Ingo
sumber