Obszary Pamięci w C/C++
2023-04-01
W językach C/C++ pamięć jest podzielona na kilka obszarów, które mają różne cele i właściwości. Oto najważniejsze obszary pamięci w C/C++:
Wysokie adresy ---> .----------------------.
| Environment |
|----------------------|
| | Funkcje i zmienne deklarowane są
| STOS | na stosie.
base pointer -> | - - - - - - - - - - -|
| | |
| v |
: :
. . Stos "rośnie w dół"
. Dostępna . Sterta "rośnie w górę"
. pamięć .
. .
. .
: :
| ^ |
| | |
brk point -> | - - - - - - - - - - -| Pamięć dynamiczna
| STERTA |
| |
|----------------------|
| BSS | Dane niezainicjowane (BSS)
|----------------------|
| Data | Dane zainicjowane (DS)
|----------------------|
| Text | Kod binarny
Niskie adresy ----> '----------------------'
- Stos (Stack): Stos jest obszarem pamięci, który przechowuje zmienne lokalne oraz informacje o wywołaniach funkcji. Stos ma charakterystykę LIFO (Last In, First Out), co oznacza, że elementy są usuwane w kolejności odwrotnej do dodania. W C/C++ stos jest używany głównie do przechowywania zmiennych o krótkim czasie życia, które są związane z czasem życia funkcji, w której są zadeklarowane.
#include <stdio.h>
int main(void)
{
int data; //zmienne lokalne przechowywane są na stosie
return 0;
}
- Sterta (Heap): Sterta to obszar pamięci, który jest używany do dynamicznego przydzielania pamięci. Sterta pozwala na przechowywanie zmiennych o długim czasie życia, które nie są związane z czasem życia funkcji. W C/C++ pamięć na stercie jest przydzielana i zwalniana za pomocą odpowiednich funkcji, takich jak malloc, calloc, realloc i free (w C) lub operatorów new i delete (w C++).
#include <stdio.h>
int main(void)
{
char *pStr = malloc(sizeof(char)*4); //przechowywane na stercie, warto pamiętać aby nie podawać wartości liczbowych bezpośrednio do sizeof()
return 0;
}
- Pamięć kodu (Code memory): Obszar ten przechowuje kod maszynowy programu. Pamięć kodu jest tylko do odczytu, co oznacza, że programista nie może modyfikować zawartości tego obszaru w trakcie działania programu.
- Pamięć danych (Data memory): Obszar pamięci danych jest podzielony na dwa podobszary: pamięć danych zainicjowanych oraz pamięć danych niezainicjowanych.
#include <stdio.h>
int main(void)
{
return 0;
}
remnux@remnux:~/Documents/code$ type wgcc
wgcc is aliased to 'x86_64-w64-mingw32-gcc'
remnux@remnux:~/Documents/code$ wgcc main.c -o main.exe
remnux@remnux:~/Documents/code$ size main.exe
text data bss dec hex filename
10728 2184 2432 15344 3bf0 main.exe
- Pamięć danych zainicjowanych (Initialized data): Ten obszar przechowuje zmienne globalne i statyczne, które są zainicjowane wartościami niezerowymi. Zmienne te są zadeklarowane na poziomie pliku lub w funkcji jako statyczne, a ich wartości są przypisane podczas kompilacji.
#include <stdio.h>
int zmienna1 = 10; // Zainicjowana zmienna globalna przechowywana w BSS
int main(void)
{
static int zmienna2 = 20; // Zainicjowana zmienna statyczna przechowywana w BSS
return 0;
}
remnux@remnux:~/Documents/code$ wgcc main.c -o z_main.exe
remnux@remnux:~/Documents/code$ size z_main.exe
text data bss dec hex filename
10728 2200 2432 15360 3c00 z_win.exe
- Pamięć danych niezainicjowanych (Uninitialized data, BSS - Block Started by Symbol): Ten obszar przechowuje zmienne globalne i statyczne, które są zainicjowane wartościami zerowymi lub nie są zainicjowane w ogóle. BSS jest zazwyczaj wyzerowany przez system operacyjny przed uruchomieniem programu.
#include <stdio.h>
int zmienna1; // Niezainicjowana zmienna globalna przechowywana w BSS
int main(void)
{
static int zmienna2; // Niezainicjowana zmienna statyczna przechowywana w BSS
return 0;
}
remnux@remnux:~/Documents/code$ wgcc main.c -o z_main.exe
remnux@remnux:~/Documents/code$ size nz_main.exe
text data bss dec hex filename
10728 2184 2464 15376 3c10 nz_win.exe
- Pamięć stałych (Constant memory): Ten obszar pamięci przechowuje stałe, takie jak literały łańcuchowe czy wartości liczbowe, które są używane w kodzie programu. Pamięć stałych jest tylko do odczytu, co oznacza, że jej zawartość nie może być modyfikowana w trakcie działania programu. W języku C++ można również korzystać z kwalifikatora const, aby zadeklarować stałe zmienne, które nie mogą być modyfikowane po zainicjowaniu.
#include <stdio.h>
char *str = "Te pieniądze im się po prostu należały";
int main(void)
{
printf("%s\n",str);
return 0;
}
remnux@remnux:~/Documents/code$ wgcc main.c -o const_main.exe
remnux@remnux:~/Documents/code$ size const_main.exe
text data bss dec hex filename
10776 2228 2432 15436 3c4c const_main.exe
Podsumowanie
W językach C/C++ pamięć jest podzielona na różne obszary, które mają różne cele i właściwości. Główne obszary pamięci to stos, sterta, pamięć kodu, pamięć danych (zainicjowanej i niezainicjowanej), rejestry procesora oraz pamięć stałych. Zrozumienie tych obszarów pamięci oraz ich zastosowań jest kluczowe dla efektywnego i bezpiecznego zarządzania pamięcią w aplikacjach C/C++.