天天看點

堆區、棧區、常量區、代碼區、靜态變量區、大小端存儲

關鍵字: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個位元組

繼續閱讀