Jika saya membuat variabel dalam set baru kurung kurawal, apakah variabel itu muncul dari tumpukan pada kurung kurawal, atau apakah itu hang out sampai akhir fungsi? Sebagai contoh:
void foo() {
int c[100];
{
int d[200];
}
//code that takes a while
return;
}
Akan d
mengambil memori selama code that takes a while
bagian?
Jawaban:
Tidak, kawat gigi tidak bertindak sebagai bingkai tumpukan. Dalam C, kawat gigi hanya menunjukkan ruang lingkup penamaan, tetapi tidak ada yang dihancurkan juga tidak ada yang muncul dari tumpukan ketika kontrol keluar dari itu.
Sebagai seorang programmer yang menulis kode, Anda sering dapat menganggapnya seolah-olah itu adalah bingkai tumpukan. Pengidentifikasi yang dideklarasikan dalam kurung kurawal hanya dapat diakses dalam kurung kurawal, jadi dari sudut pandang seorang programmer, sepertinya mereka didorong ke tumpukan seperti yang dideklarasikan dan kemudian muncul ketika cakupan keluar. Namun, kompiler tidak harus membuat kode yang mendorong / muncul apa pun saat masuk / keluar (dan umumnya, mereka tidak).
Perhatikan juga bahwa variabel lokal mungkin tidak menggunakan ruang stack sama sekali: mereka dapat disimpan dalam register CPU atau di beberapa lokasi penyimpanan tambahan lainnya, atau dioptimalkan sepenuhnya.
Jadi,
d
array, secara teori, dapat mengkonsumsi memori untuk seluruh fungsi. Namun, kompiler dapat mengoptimalkannya, atau berbagi memorinya dengan variabel lokal lainnya yang masa pakainya tidak tumpang tindih.sumber
Waktu di mana variabel benar - benar mengambil memori jelas tergantung pada kompiler (dan banyak kompiler tidak menyesuaikan penumpukan tumpukan ketika blok bagian dalam dimasukkan dan keluar dalam fungsi).
Namun, pertanyaan yang erat terkait tetapi mungkin lebih menarik adalah apakah program diizinkan untuk mengakses objek dalam itu di luar lingkup dalam (tetapi dalam fungsi yang mengandung), yaitu:
(Dengan kata lain: apakah kompiler diperbolehkan untuk melakukan deallocate
d
, walaupun dalam praktiknya kebanyakan tidak?).Jawabannya adalah bahwa compiler yang diperbolehkan untuk deallocate
d
, dan mengaksesp[0]
di mana komentar menunjukkan adalah perilaku undefined (program ini tidak diperbolehkan untuk akses di luar objek dalam dari ruang lingkup batin). Bagian yang relevan dari standar C adalah 6.2.4p5:sumber
Pertanyaan Anda tidak cukup jelas untuk dijawab dengan jelas.
Di satu sisi, kompiler biasanya tidak melakukan alokasi alokasi-memori lokal untuk ruang lingkup blok bersarang. Memori lokal biasanya dialokasikan hanya sekali pada entri fungsi dan dirilis pada keluar fungsi.
Di sisi lain, ketika masa hidup objek lokal berakhir, memori yang ditempati oleh objek itu dapat digunakan kembali untuk objek lokal lain nanti. Misalnya, dalam kode ini
kedua array biasanya akan menempati area memori yang sama, artinya jumlah total penyimpanan lokal yang dibutuhkan oleh fungsi
foo
adalah apa pun yang diperlukan untuk yang terbesar dari dua array, bukan untuk keduanya sekaligus.Apakah yang terakhir memenuhi syarat sebagai
d
terus menempati ingatan sampai akhir fungsi dalam konteks pertanyaan Anda, apakah Anda yang memutuskan.sumber
Tergantung implementasi. Saya menulis sebuah program pendek untuk menguji apa yang dilakukan gcc 4.3.4, dan ia mengalokasikan semua ruang stack sekaligus pada awal fungsi. Anda dapat memeriksa perakitan yang diproduksi gcc menggunakan flag -S.
sumber
Tidak, d [] tidak akan ada di tumpukan selama sisa rutin. Tetapi pengalokasian () berbeda.
Sunting: Kristopher Johnson (dan simon dan Daniel) benar , dan tanggapan awal saya salah . Dengan gcc 4.3.4.pada CYGWIN, kode:
memberi:
Hidup dan belajar! Dan tes cepat tampaknya menunjukkan bahwa AndreyT juga benar tentang alokasi ganda.
Ditambahkan jauh kemudian : Tes di atas menunjukkan dokumentasi gcc tidak tepat. Selama bertahun-tahun dikatakan (penekanan ditambahkan):
sumber
alloca
fungsi. Saya sangat terkejut bahwa cygwin gcc akan melakukan itu. Itu bahkan bukan array panjang variabel, jadi IDK mengapa Anda memunculkannya.Mereka mungkin. Mungkin tidak. Jawaban yang menurut saya sangat Anda butuhkan adalah: Jangan pernah berasumsi apa pun. Kompiler modern mengerjakan semua jenis arsitektur dan implementasi khusus sihir. Tulis kode Anda secara sederhana dan jelas kepada manusia dan biarkan kompiler melakukan hal-hal yang baik. Jika Anda mencoba kode di sekitar kompiler Anda meminta masalah - dan masalah yang biasanya Anda dapatkan dalam situasi ini biasanya sangat halus dan sulit untuk didiagnosis.
sumber
Variabel Anda
d
biasanya tidak muncul dari tumpukan. Kurung kurawal tidak menunjukkan bingkai tumpukan. Jika tidak, Anda tidak akan dapat melakukan hal seperti ini:Jika kurung kurawal menyebabkan stack push / pop yang sebenarnya (seperti panggilan fungsi akan), maka kode di atas tidak akan dikompilasi karena kode di dalam kurung kurawal tidak akan dapat mengakses variabel
var
yang hidup di luar kurung kurawal (sama seperti sub- fungsi tidak dapat langsung mengakses variabel dalam fungsi panggilan). Kita tahu ini bukan masalahnya.Kurung kurawal hanya digunakan untuk pelingkupan. Kompiler akan memperlakukan setiap akses ke variabel "dalam" dari luar kurung kurawal sebagai tidak sah, dan mungkin menggunakan kembali memori itu untuk sesuatu yang lain (ini tergantung pada implementasi). Namun, itu mungkin tidak muncul dari tumpukan sampai fungsi penutup kembali.
Update: Inilah yang C spek katakan. Mengenai benda-benda dengan durasi penyimpanan otomatis (bagian 6.4.2):
Bagian yang sama mendefinisikan istilah "seumur hidup" sebagai (penekanan milikku):
Kata kuncinya di sini adalah, tentu saja, 'dijamin'. Setelah Anda meninggalkan ruang lingkup set kawat gigi dalam, masa pakai array sudah berakhir. Penyimpanan mungkin atau mungkin masih belum dialokasikan untuk itu (kompiler Anda mungkin menggunakan kembali ruang untuk sesuatu yang lain), tetapi setiap upaya untuk mengakses array memicu perilaku yang tidak terdefinisi dan membawa hasil yang tidak terduga.
C spec tidak memiliki gagasan tentang stack frame. Itu hanya berbicara tentang bagaimana program yang dihasilkan akan berperilaku, dan meninggalkan detail implementasi ke kompiler (setelah semua, implementasi akan terlihat sangat berbeda pada CPU tanpa tumpukan dibandingkan pada CPU dengan tumpukan perangkat keras). Tidak ada dalam spesifikasi C yang mengamanatkan di mana frame stack akan atau tidak akan berakhir. Satu-satunya cara nyata untuk mengetahui adalah mengkompilasi kode pada kompiler / platform khusus Anda dan memeriksa rakitan yang dihasilkan. Pilihan optimisasi kompiler Anda saat ini kemungkinan juga akan berperan dalam hal ini.
Jika Anda ingin memastikan bahwa array
d
tidak lagi menghabiskan memori saat kode Anda sedang berjalan, Anda dapat mengonversi kode dalam kurung kurawal menjadi fungsi terpisah atau secara eksplisitmalloc
danfree
memori alih-alih menggunakan penyimpanan otomatis.sumber
Saya percaya bahwa itu keluar dari ruang lingkup, tetapi tidak muncul dari tumpukan sampai fungsi kembali. Jadi masih akan mengambil memori pada stack sampai fungsi selesai, tetapi tidak dapat diakses di hilir kurung kurawal penutupan pertama.
sumber
Sudah ada banyak informasi mengenai standar yang mengindikasikan bahwa ini memang implementasi spesifik.
Jadi, satu percobaan mungkin menarik. Jika kami mencoba kode berikut:
Menggunakan gcc yang kami dapatkan di sini dua kali alamat yang sama: Coliro
Tetapi jika kita mencoba kode berikut:
Dengan menggunakan gcc, kami memperoleh dua alamat berbeda di sini: Coliro
Jadi, Anda tidak dapat benar-benar yakin apa yang sedang terjadi.
sumber