Değişkenlerim C'de nerede saklanıyor?


156

Belleğin dört bölüme ayrıldığını göz önünde bulundurarak: küresel değişkenler, statik değişkenler, sabit veri türleri, yerel değişkenler (işlevlerde tanımlanmış ve bildirilmiş), değişkenler (ana işlevde), işaretçiler nerede; veri, yığın, yığın ve kod ve dinamik olarak tahsis edilen alan (malloc ve calloc kullanarak) bellekte depolanıyor mu?

Bence onlar aşağıdaki gibi tahsis edilecektir:

  • Global değişkenler -------> veri
  • Statik değişkenler -------> veri
  • Sabit veri türleri -----> kodu
  • Yerel değişkenler (işlevlerde bildirilmiş ve tanımlanmış) --------> yığın
  • Ana işlevde bildirilen ve tanımlanan değişkenler -----> yığın
  • İşaretçiler (örneğin char *arr, int *arr) -------> yığın
  • Dinamik olarak ayrılmış alan (malloc ve calloc kullanarak) --------> yığın

Bu değişkenlere sadece C açısından bakıyorum.

C için yeni olduğum için yanlışsam lütfen beni düzeltin


4
Türler bellekte saklanmaz.

5
mainsadece başka bir işlevdir. Değişkenler malloctıpkı başka bir yerde olmadığı sürece yığının üstüne gider .
simonc

4
işaretçiler (genellikle) yığın üzerinde saklanır. İşaret ettikleri bellek (genellikle malloc / calloc ile tahsis edilir) öbek üzerinde (genellikle) bulunur.
jpm

3
dinamik olarak ayrılmış alan (malloc, calloc kullanarak) --------> yığın
One Man Crew

3
ana fonksiyonda açıklanan ve tanımlanan değişkenler -----> yığın
One Man Crew

Yanıtlar:


217

Bunlardan bazılarını hakkın var, ama soruları yazan kişi seni en az bir soru üzerine kandırdı:

  • global değişkenler -------> veri (doğru)
  • statik değişkenler -------> veri (doğru)
  • sabit veri türleri -----> kod ve / veya veri. Veri segmentinde bir sabitin kendisinin saklanacağı ve ona yapılan referansların koda gömüleceği bir durum için dize değişmezlerini göz önünde bulundurun
  • yerel değişkenler (fonksiyonlarda bildirilmiş ve tanımlanmıştır) --------> yığın (doğru)
  • mainişlevi -----> yığınında bildirilen ve tanımlanan değişkenler de yığın (öğretmen sizi kandırmaya çalışıyordu)
  • işaretçiler (ör char *arr, int *arr) -------> yığın içeriğe bağlı olarak veri veya yığın. C, genel veya bir staticişaretçiyi bildirmenize izin verir , bu durumda işaretçinin kendisi veri segmentinde kalır.
  • Dinamik alan tahsis (kullanarak malloc, calloc, realloc) --------> yığın yığın

"Yığın" resmen "otomatik depolama sınıfı" olarak adlandırılır.


6
Ayrıca, yığının resmen hiçbir şey olarak adlandırılmadığını da belirtmek gerekir. Ayrılan bellek bir yerden gelir, standartta bu "bir yer" için bir isim yoktur.
Steve Jessop

6
Bazı sistemlerde (yani Linux ve * BSD) allocabenzer şekilde çalışan malloc, ancak yığın tahsisi yapan da vardır.
Andreas Grapentin

Bir yöntem içinde bildirilen const değişkeni nereye gider?
Mahori

@Ravi Sabitlerin geri kalanı aynı yere gider (yukarıdaki 3. nokta).
dasblinkenlight

GCC 4.8.1 kullanıyorum ve const değişkeni yerel olarak ana veri depolamak için görünmüyor. Bu tür 3 program için kod ve bellek haritası aşağıdadır: Kod 1: int main (void) {// char a [10] = "HELLO"; // 1 // const char a [10] = "HELLO"; // 2 dönüş 0; } YUKARIDA BELLEK HARİTASI: metin verileri bss dec hex dosya adı 7264 1688 1040 9992 2708 a.exe 2 İÇİN BELLEK HARİTASI: metin verileri bss dec hex dosya adı 7280 1688 1040 10008 2718 a.exe 3 İÇİN BELLEK HARİTASI: metin verileri bss dec hex dosya adı 7280 1688 1040 10008 2718 a.exe
Mahori

124

Bu bellek segmentleri hakkında bilgi edinmek isteyen gelecekteki ziyaretçiler için, C'deki 5 bellek segmenti hakkında önemli noktalar yazıyorum:

Bazıları başa gelir:

  1. Bir C programı yürütüldüğünde, RAM'in programın yürütülmesi için bir miktar bellek ayrılır. Bu bellek, sık çalıştırılan kodu (ikili veri), program değişkenlerini, vb. Saklamak için kullanılır. Aşağıdaki bellek segmentleri aşağıdakilerden bahseder:
  2. Genellikle üç tür değişken vardır:
    • Yerel değişkenler (C'de otomatik değişkenler olarak da adlandırılır)
    • Global değişkenler
    • Statik değişkenler
    • Genel statik veya yerel statik değişkenleriniz olabilir, ancak yukarıdaki üçü üst türlerdir.

C'deki 5 Bellek Segmenti:

1. Kod Segmenti

  • Metin segmenti olarak da adlandırılan kod segmenti, sık sık yürütülen kodu içeren bellek alanıdır.
  • Tampon taşması gibi hataları programlayarak geçersiz kılma riskini önlemek için kod segmenti genellikle salt okunurdur.
  • Kod segmenti, yerel değişken ( C'de otomatik değişkenler olarak da bilinir ), global değişkenler vb. Gibi program değişkenleri içermez .
  • C uygulamasına bağlı olarak, kod segmenti salt okunur dize değişmez değerleri içerebilir. Örneğin, printf("Hello, world")"Merhaba, dünya" dizesini yaptığınızda kod / metin segmentinde oluşturulur. sizeLinux işletim sistemindeki komutu kullanarak bunu doğrulayabilirsiniz .
  • daha fazla okuma

Veri Segmenti

Veri segmenti aşağıdaki iki parçaya bölünür ve tipik olarak yığın alanının altında veya yığının üzerindeki bazı uygulamalarda bulunur, ancak veri segmenti asla yığın ve yığın alanı arasında yer almaz.

2. Başlatılmamış veri segmenti

  • Bu segment bss olarak da bilinir .
  • Bu, belleğin aşağıdakileri içeren kısmıdır:
    1. Başlatılmamış global değişkenler (işaretçi değişkenleri dahil)
    2. Başlatılmamış sabit global değişkenler .
    3. Başlatılmamış yerel statik değişkenler .
  • Başlatılmamış herhangi bir genel veya statik yerel değişken, başlatılmamış veri segmentinde saklanır
  • Örneğin: global değişken int globalVar;veya statik yerel değişken static int localStatic;, başlatılmamış veri segmentinde saklanır.
  • Genel bir değişken bildirir ve bunu 0veya olarak başlatırsanız, NULLyine de başlatılmamış veri segmentine veya bss'ye gider.
  • daha fazla okuma

3. Başlatılan veri segmenti

  • Bu segment şunları depolar:
    1. Başlatılmış global değişkenler (işaretçi değişkenleri dahil)
    2. Başlatılan sabit global değişkenler .
    3. Başlatılan yerel statik değişkenler .
  • Örneğin: global değişken int globalVar = 1;veya statik yerel değişken static int localStatic = 1;, başlatılan veri segmentinde saklanır.
  • Bu segment ayrıca başlatılmış salt okunur alana ve başlatılmış okuma-yazma alanına sınıflandırılabilir . Başlatılan sabit genel değişkenler başlatılan salt okunur alana, değerleri çalışma zamanında değiştirilebilen değişkenler başlatılan salt okunur alana gider .
  • Bu bölümün boyutu, programın kaynak kodundaki değerlerin boyutuna göre belirlenir ve çalışma zamanında değişmez .
  • daha fazla okuma

4. Yığın Segmenti

  • Yığın segmenti, işlevler içinde oluşturulan değişkenleri depolamak için kullanılır ( işlev ana işlev veya kullanıcı tanımlı işlev olabilir ), değişken
    1. İşlevin yerel değişkenleri (işaretçi değişkenleri dahil)
    2. İşleve iletilen bağımsız değişkenler
    3. İade adresi
  • Yığında depolanan değişkenler, işlev yürütme tamamlanır tamamlanmaz kaldırılır.
  • daha fazla okuma

5. Yığın Segmenti

  • Bu segment dinamik bellek tahsisini desteklemek içindir. Programcı C dinamik sonra bazı bellek ayırmaya istiyorsa o kullanılarak yapılır malloc, callocya da reallocyöntemler.
  • Örneğin, o int* prt = malloc(sizeof(int) * 2)zaman sekiz bayt yığın halinde tahsis edilecek ve o yerin hafıza adresi döndürülecek ve ptrdeğişken içinde saklanacaktır . ptrDeğişken ya da kullanılmış / ilan edilir şekilde bağlı yığın ya da veri segmenti olacaktır.
  • daha fazla okuma

Başlatılmamış veri bölümünde 3. başlatılmak yerine başlatılmamalıdır.
Suraj Jain

Yeniden "başlatılmamış veri segmentinde saklanır" (birden çok örnek): "Veri segmentinde başlatılmamış olarak saklanır" mı demek istediniz ?
Peter Mortensen

@PeterMortensen Her iki şeyi de kastediyorum. "Başlatılmamış herhangi bir genel veya statik yerel değişken başlatılmamış veri segmentinde saklanacaktır"
hagrawal

C'de global statik değişkene nasıl sahip olabiliriz?

"bazı başlıklar" altında bu noktayı buldum "Global statik veya yerel statik değişkenlere sahip olabilirsiniz, ancak yukarıdaki üçü ana türlerdir." burada u "global statik" terimine atıfta bulunur. Demek istediğim statik bir değişken global olamaz. yani, herhangi bir değişkenin global olması gerekiyorsa, programın yürütülmesi tamamlanana kadar erişilebilir olmalıdır. Yanılıyorsam lütfen açıklayın ve yardım edin.

11

Yanlış cümleleriniz düzeltildi

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

yerel sabit değişkenler -----> yığın

başlatılan global sabit değişken -----> veri segmenti

başlatılmamış global sabit değişken -----> bss

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

ana fonksiyonda tanımlanmış ve tanımlanmış değişkenler -----> yığın

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

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

işaretçiler (ör: char * arr, int * arr) -------> o işaretçi değişkeninin boyutu yığın halinde olacaktır.

N bayt hafızasını ( mallocveya kullanarak calloc) dinamik olarak ayırdığınızı ve ardından işaret etmek için işaretçi değişkeni yaptığınızı düşünün . Şimdi nbellek baytları yığın halinde ve işaretçi değişkeni n, bellek yığınının baytlarının başlangıç ​​işaretçisini saklamak için yığın halinde olacak olan 4 bayt (64 bit makine 8 bayt ise) gerektirir .

Not: İşaretçi değişkenleri herhangi bir segmentin belleğini gösterebilir.

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
...
}

dinamik olarak ayrılmış alan (malloc, calloc kullanarak) --------> yığın


işaretçiler yığın veya yığın halinde olabilir (özellikle bakın: işaretçilerden işaretçilere)
argüman

@airza: Şimdi güncellendi. AKTually ben sadece bu ayrıntıları güncelleme oldu :)
rashok

Aşağıdaki hafıza haritasında lütfen yığın ve yığının nerede olduğunu belirtebilir misiniz? Yığın ve bellek yalnızca çalışma zamanında geçerli olabileceğinden, bu sorunun doğru olup olmadığından emin değilim. BELLEK HARİTASI: "metin verileri bss aralık altıgen dosya adı 7280 1688 1040 10008 2718 a.exe"
Mahori

7

Popüler bir masaüstü mimarisi, bir işlemin sanal belleğini birkaç segmente ayırır :

  • Metin segmenti: yürütülebilir kodu içerir. Talimat işaretçisi bu aralıktaki değerleri alır.

  • Veri segmenti: global değişkenler içerir (yani statik bağlantılı nesneler). Salt okunur veri (dize sabitleri gibi) ve başlatılmamış veriler ("BSS") olarak alt bölümlere ayrılmıştır.

  • Yığın segmenti: programın dinamik belleğini içerir; yani, serbest iş parçacığı ("yığın") ve tüm iş parçacıkları için yerel yığın çerçeveleri. Geleneksel olarak C yığını ve C yığını, ters uçlardan yığın segmentine doğru büyürdü, ancak çok güvensiz olduğu için uygulamanın terk edildiğine inanıyorum.

AC programı genellikle statik depolama süresine sahip nesneleri veri segmentine, serbest depoda dinamik olarak atanan nesneleri ve içinde bulunduğu iş parçacığının çağrı yığınına otomatik nesneleri koyar.

Eski x86 gerçek modu gibi diğer platformlarda veya gömülü cihazlarda işler açıkça farklı olabilir.


"Çok güvensiz olduğu için uygulamanın terk edildiğine inanıyorum" - ve iş parçacıklarının uygulanmasını imkansız kılıyor, çünkü o zamandan beri program başına birden fazla yığına ihtiyacınız var ve hepsi sonunda olamaz :-)
Steve Jessop

@SteveJessop: Evet, ben de düşünüyordum. Ama iplikler uzun zamandır var - tüm iplik yığınlarının da geriye doğru büyüyüp büyüyüp büyümediğini bilmiyorum ya da yığın gibi büyüyecekler ... neyse, bugünlerde her şey aynı yöne gidiyor ve bekçi var sayfaları.
Kerrek SB

6

Bu değişkenlere sadece C açısından bakıyorum.

C dili açısından, önemli olan tek şey kapsam, kapsam, bağlantı ve erişim; öğelerin farklı bellek segmentleriyle tam olarak nasıl eşleştirildiği tek tek uygulamaya bağlıdır ve bu değişecektir. Dil standart bellek kesimleri hakkında konuşmak olmaz hiç . Modern mimarilerin çoğu çoğunlukla aynı şekilde hareket eder; blok-kapsam değişkenleri ve fonksiyon argümanları yığından, dosya-kapsamı ve statik değişkenler bir veri veya kod segmentinden, dinamik bellek bir yığıntan tahsis edilecek, bazı sabit veriler salt okunur segmentlerde depolanacaktır , vb.


3

Depolama hakkında akılda tutulması gereken bir şey as-if kuralıdır . Derleyicinin belirli bir yere bir değişken koyması gerekmez - bunun yerine, derlenmiş program soyut C makinesinde soyut C makinesinin kurallarına göre çalıştırılmış gibi davrandığı sürece onu istediği yere yerleştirebilir . Bu, tüm depolama süreleri için geçerlidir . Örneğin:

  • erişilemeyen bir değişken tamamen ortadan kaldırılabilir - depolaması yoktur ... hiçbir yerde. Örnek - 42oluşturulan montaj kodunda nasıl olduğunu görün, ancak hiçbir iz yok 404.
  • adresi alınmayan otomatik saklama süresine sahip bir değişkenin belleğe kaydedilmesi gerekmez. Örnek bir döngü değişkeni olabilir.
  • bellekte olması constveya etkin bir şekilde constolması gerekmeyen bir değişken . Örnek - derleyici foobunun etkili olduğunu kanıtlar constve kullanımını koda dönüştürür. barharici bir bağlantıya sahiptir ve derleyici, mevcut modülün dışında değiştirilmeyeceğini kanıtlayamaz, bu nedenle satır içi değildir.
  • ayrılan bir nesnenin mallocyığından ayrılan bellekte kalmasına gerek yoktur! Örnek - kodun nasıl çağrılmadığına dikkat edin mallocve bellekte hiç 42 değeri saklanmadı, bir kayıt defterinde tutulur!
  • bu nedenle tahsis edilen bir nesne mallocve referans bellek sızıntısı free olmayan nesneyi dağıtmadan kaybolur ...
  • tarafından ayrılan nesnenin Unixen'deki program sonu ( ) altındakimalloc yığın içinde olması gerekmez ...sbrk(0)

1

işaretçiler (ör: char * arr, int * arr) -------> öbek

Hayır, yığın üzerinde veya veri segmentinde olabilirler. Herhangi bir yeri gösterebilirler.


mainDeğişkenlerle ilgili ve dinamik olarak atanan ifadeler de yanlış
simonc

Sadece yığın veya veri segmentinde değil. Bir işaretçi dizisini gösteren bir işaretçi düşünün. Bu durumda dizideki işaretçiler yığın üzerinde saklanır.
Sebi2020

1
  • Değişkenler / otomatik değişkenler ---> yığın bölümü
  • Dinamik olarak ayrılmış değişkenler ---> yığın bölümü
  • Başlatılan global değişkenler -> veri bölümü
  • Başlatılmamış global değişkenler -> veri bölümü (bss)
  • Statik değişkenler -> veri bölümü
  • Dize sabitleri -> metin bölümü / kod bölümü
  • İşlevler -> metin bölümü / kod bölümü
  • Metin kodu -> metin bölümü / kod bölümü
  • Kayıtlar -> CPU kayıtları
  • Komut satırı girişleri -> çevre / komut satırı bölümü
  • Çevresel değişkenler -> çevresel / komut satırı bölümü

Çevre / komut satırı bölümü nedir? Linux'ta var mı?
Haoyuan Ge

-1

Sökme analizine sahip Linux ile minimum çalıştırılabilir örnekler

Bu, standartlar tarafından belirtilmeyen bir uygulama ayrıntısı olduğundan, derleyicinin belirli bir uygulamada ne yaptığını inceleyelim.

Bu cevapta, analizi yapan spesifik cevaplarla bağlantı kuracağım veya doğrudan burada analiz sağlayacağım ve tüm sonuçları burada özetleyeceğim.

Bunların hepsi çeşitli Ubuntu / GCC sürümlerinde ve sonuçlar sürümler arasında oldukça kararlı, ancak herhangi bir varyasyon bulursak daha kesin sürümler belirleyelim.

Bir fonksiyon içindeki yerel değişken

İster mainbaşka bir fonksiyon olsun:

void f(void) {
    int my_local_var;
}

Gösterildiği gibi: gdb'de <optimize edilmiş değer> ne anlama geliyor?

  • -O0: yığın
  • -O3: dökülmezlerse kaydolur, aksi halde istifler

Yığının neden var olduğuna dair motivasyon için bkz: x86 derlemesindeki kayıtlarda kullanılan push / pop talimatlarının işlevi nedir?

Global değişkenler ve staticfonksiyon değişkenleri

/* 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;
}
  • başlatıldı eğer 0ya da değil başlatıldı (ve bu nedenle dolaylı olarak başlatıldı 0): .bssbölüm, ayrıca bkz: Neden .bss segmenti gereklidir?
  • aksi takdirde: .databölüm

char * ve char c[]

Gösterildiği gibi: Statik değişkenler C ve C ++ 'da nerede saklanır?

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

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

YAPILACAKLAR Çok büyük dize değişmezleri de yığına konacak mı? Yoksa .data? Yoksa derleme başarısız mı?

İşlev bağımsız değişkenleri

void f(int i, int j);

İlgili çağrı kuralından geçmelidir, örneğin: her değişken için belirli kayıtları veya yığın konumlarını belirten X86 için https://en.wikipedia.org/wiki/X86_calling_conventions .

Daha sonra gösterildiği gibi <optimize edilmiş değer> gdb'de ne anlama geliyor? , -O0daha sonra kayıtları -O3mümkün olduğunca kullanmaya çalışırken , her şeyi yığına kaydırır .

Ancak işlev satır içine girerse, normal yerliler gibi davranılır.

const

Fark etmediğine inanıyorum çünkü tahmin edebiliyorsunuz.

Tersine, eğer derleyici bazı verinin asla yazılmadığını belirleyebiliyorsa, teorik olarak veri .rodataolmasa bile veriyi yerleştirebilir .

YAPILACAKLAR analizi.

İşaretçiler

Değişkenlerdir (sayı içeren adresler içerir), diğerleriyle aynı :-)

malloc

Sorusu için çok mantıklı değil malloc, çünkü mallocbir fonksiyondur ve içinde:

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

*i adres içeren bir değişkendir, bu nedenle yukarıdaki duruma düşer.

Malloc'un dahili olarak nasıl çalıştığına gelince, Linux çekirdeği olarak adlandırdığınızda, Linux çekirdeği belirli adresleri dahili veri yapılarında yazılabilir olarak işaretler ve başlangıçta program tarafından dokunulduğunda, bir hata olur ve çekirdek, erişime izin veren sayfa tablolarını etkinleştirir. segfaul olmadan olur: x86 sayfalama nasıl çalışır?

Bununla birlikte, temelde execbir çalıştırılabilir dosyayı çalıştırmaya çalıştığınızda syscall'ın tam olarak kaputun altında yaptığı şey olduğunu unutmayın : yüklemek istediği sayfaları işaretler ve programı oraya yazar, ayrıca bkz: Çekirdek altında çalışan bir yürütülebilir ikili dosyayı nasıl alır? linux? Bunun execnereye yükleneceği konusunda bazı ekstra sınırlamaları dışında (örneğin, kodun yeri değiştirilemez ).

İçin kullanılan tam syscall mallocolan mmapModern 2020 uygulamalarda ve geçmişte brkkullanılmıştır: mu malloc () kullanımı brk () veya mmap ()?

Dinamik kütüphaneler

Temelde mmaphafızaya alın: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

envinroment değişkenler ve mainsitesindekiargv

İlk yığının üstünde: /unix/75939/where-is-the-environment-string-actual-stored TODO neden .data'da olmasın?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.