關鍵字:visual studio 2019; C++; 堆區; 棧區; 常量區; 代碼區; 靜态變量; 記憶體配置設定; 位址;
測試環境:visual studio 2019 x86(32bit);Debug模式;
注:本篇測試内容僅供參考,也歡迎各位與我交流。
什麼是代碼區、常量區、靜态區(全局區)、堆區、棧區?
代碼區:存放程式的代碼,即CPU執行的機器指令,并且是隻讀的。
常量區:存放常量(程式在運作的期間不能夠被改變的量,例如: 10,字元串常量”abcde”, 數組的名字等)
靜态區(全局區):靜态變量和全局變量的存儲區域是一起的,一旦靜态區的記憶體被配置設定, 靜态區的記憶體直到程式全部結束之後才會被釋放
堆區:由程式員調用malloc()函數來主動申請的,需使用free()函數來釋放記憶體,若申請了堆區記憶體,之後忘記釋放記憶體,很容易造成記憶體洩漏
棧區:存放函數内的局部變量,形參和函數傳回值。棧區之中的資料的作用範圍過了之後,系統就會回收自動管理棧區的記憶體(配置設定記憶體 , 回收記憶體),不需要開發人員來手動管理。棧區就像是一家客棧,裡面有很多房間,客人來了之後自動配置設定房間,房間裡的客人可以變動,是一種動态的資料變動。
大小端測試:
uint32_t b = 0x20103321;
int main()
{
// 大小端測試
int w = 0x33521241;
printf("靜态區測試大小端儲存方式\n");
printf("uint32_t - b:%p:%x\n", &b, b);
char* p = (char*)&b;
int i;
for (i = 0; i < 4; ++i)
{
printf("%d:%p:%x\n", i, p + i, *(p + i));
}
printf("測試棧區存儲方式\n");
printf("int - w:%p:%x\n", &w, w);
char* pw = (char*)&w;
for (i = 0; i < 4; ++i)
{
printf("%d:%p:%x\n", i, pw + i, *(pw + i));
}
}
output:
結論:這裡我們靜态區變量b的值為0x20103321 占4個位元組,靜态區位址從低位到高位。
首位址是0x004DA004,存儲的是21、位址0x004DA005存儲的是33、0x004DA006存儲10、0x004DA007存儲20。
可以看出從位址低位到高位依次存儲uint32_t b 21 33 10 20;從小端開始存儲,是以我的電腦為小端存儲;
然後我非常好奇,如果是位址從高位到低位的棧區,其中整形的小端存儲模式會變化嗎?于是我做了測試得出了結論;
棧中變量w的值為0x33521241,棧區位址從高位到低位.
首位址是0x010FFA68,存儲的是41、位址0x010FFA69,存儲的是12、0x010FFA6A,存儲的是52、0x010FFA6B,存儲的是33。
可以看出從位址低位到高位依次存儲int w 41 12 52 33;從小端開始存儲。
是以得出最終結論:小端存儲不受位址流向的影響,都是低位址到高位址按小端開始的方式存儲。
棧區:
int main()
{
int e = 1117;
int f = 220;
int g = 1220;
// 棧區
printf("棧區\n");
printf("int - e:0x%p:%d\n", &e, e);
printf("int - f:0x%p:%d\n", &f, f);
printf("int - g:0x%p:%d\n", &g, g);
return 0;
}
output:
結論:每個int在Debug模式下占12個位元組,這是因為Debug模式下vs向int型前後各添加了4個位元組便于調試。在我電腦C++(x86/32bit)模式下,sizeof(int) 等于4;
f = 0x00EFFE4C - 0x00EFFE40 = 12;
g = 0x00EFFE40 - 0x00EFFE34 = 12;
這裡得出結論,棧區位址從高位到低位;
堆區:
#define calloc(num, size) (int *)calloc(num, size)
int main()
{
int *value = calloc(1,sizeof(int));
int* value2 = calloc(1, sizeof(int));
if (value == NULL)
return 0;
if (value2 == NULL)
return 0;
*value = 12345;
*value2 = 88521;
// 堆區
printf("堆區\n");
printf("int - value1:0x%p:%d\n", value, *value);
printf("int - value1 addres:0x%p\n", &value);
printf("int - value2:0x%p:%d\n", value2, *value2);
printf("int - value2 addres:0x%p\n", &value2);
free(value);
printf("free int - value1:0x%p:%d\n", value, *value);
value = NULL;
printf("NULL int - value1:0x%p\n", value);
free(value2);
return 0;
}
output:
結論:這裡位址移動特别快呀!(QAQ)
我也不知道為啥,但是我們暫時先不管這個。
value1指針的位址存在0x0044F940;
value1被釋放掉後指向的位址不變,需要執行指向NULL操作,不然有時候操作會錯誤;
他的位址也是從低位到高位;
靜态區:
uint32_t a = 0x20000000;
uint32_t b = 0x20103321;
int c = 24;
int d = 4332;
int main()
{
// 靜态區
printf("靜态區\n");
printf("uint32_t - a:0x%p:%x\n", &a, a);
printf("uint32_t - b:0x%p:%x\n", &b, b);
printf("int -c:0x%p:%d\n", &c, c);
printf("int -d:0x%p:%d\n", &d, d);
return 0;
}
output:
結論:此處每個int/uint32_t占4個位元組
a的長度等于 0x0101A004-0x0101A000 = 4 符合
b的長度等于 0x0101A008-0x0101A004 = 4 符合
c的長度等于 0x0101A00C-0x0101A008 = 4 符合
結論靜态區(全局區)位址從低位到高位;
常量區:
int main()
{
const char* h = "assdas";
const char* k = "wehasdasdasdst";
const char* m = "weht";
// 常量區
printf("常量區\n");
printf("const char* - h:0x%p:%s\n", h, h);
printf("const char* - k:0x%p:%s\n", k, k);
printf("const char* - m:0x%p:%s\n", m, m);
return 0;
}
output:
(此處是在Release模式下的測試結果,在Debug模式上則有偏差,這點求高手解答)
結論:char 字元占1bit ,這裡每個字元串會在前後自動添加一個'\0'末尾符,于是每個字元串都要在它基礎的長度上再加2個位元組。
h字元串長度為6 + 2 = 8
位址0x00D73270 - 0x00D73268 = 8;
h字元串長度為14 + 2 = 16
位址0x00D73280 - 0x00D73270 = 16;
常量區記憶體位址從低位到高位;
代碼區:
void test() {
printf("1:hello world!");
}
void test2() {
printf("2:hello world!");
}
void test3();
int main()
{
// 代碼區
printf("代碼區\n");
printf("main:0x%p\n", &main);
printf("function - test1:0x%p\n", &test);
printf("function - test2:0x%p\n", &test2);
printf("function - test3:0x%p\n", &test3);
reurn 0
}
void test3() {
printf("3:hello world!");
}
output:
結論:代碼區記憶體大小不固定,位址從高位到低位;(這裡不太懂,有懂編譯的同學可以幫我糾正一下。)
參考連結
https ://blog.csdn.net/u014470361/article/details/79297601 - 什麼是代碼區、常量區、靜态區(全局區)、堆區、棧區?
https://blog.csdn.net/weixin_34220623/article/details/86266444 - 棧上連續定義的int變量,位址相差12個位元組