天天看点

堆区、栈区、常量区、代码区、静态变量区、大小端存储

关键字: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个字节

继续阅读