汉扬编程 编程大纲 C语言内存分布(内核区、堆栈区等)

C语言内存分布(内核区、堆栈区等)

C语言内存分布(内核、变量,堆栈等)

C语言内存分布(内核区、堆栈区等)

内核区是提供给操作系统使用的。栈区是给局部变量使用的,局部变量是函数内定义的变量,包括函数系数;程序调用时把局部变量存的数据压入栈,程序退出时把局部变量存的数据弹出栈,压栈-栈指针指向此次所压数据的最底端;出栈-栈指针指向此次所压数据的最顶端,栈区向下增长即数据随着压栈往下存储(如图2所示)。局部变量的作用范围是函数调用时生效,函数退出时失效。

C语言内存分布(内核区、堆栈区等)

动态链接库是程序运行时所需的库。堆区是函数malloc申请的内存区,堆区向上增长即随着malloc申请的次数曾多往上占用空间(不一定存储数据)。

bss是未初始化的全局变量(在所有函数外申请的变量)和未初始化的静态变量(static修饰的变量)区,例如编写day.c文件int a; int main(void){…return 0;} int day(void){static int b;…return 0;},其中a是未初始化的全局变量,b是未初始化的静态变量。

data区是已初始化的全局变量和已初始化的静态变量区,例如前面的int a=112;…static int b=113;…,其中a是已初始化的全局变量,b是已初始化的静态变量。

只读数据区是给字符串常量存储的,例如字符串“Hello NMLINUX”等。

代码区是给正在运行或者将要运行的程序用的。

(C语言内存分布图如图1所示)。

图1、C语言内存分布图

图2、C语言栈图

C|程序存储分区及栈内存区的局部变量压栈和出栈顺序

直接看下面代码:

C语言内存分布(内核区、堆栈区等)

#if(1)#include<iostream>using namespace std;int gi1 = 0; //全局初始化区int gi2 = 0; //全局初始化区int g1; //全局未初始化区int g2; //全局未初始化区char *p1; //全局未初始化区void func(int **p) //函数名可以表示函数代码所在的地址{ *p=new int[5]; delete [] p;}void main(int argc, int* argv[]){ int sb; //栈 char s[] = \”abc\”; //栈 char *p2; //栈 char *p3 = \”def\”; //123456{post.content}在常量区,p3在栈上 static int c = 0; //全局(静态)初始化区 p1 = (char *)malloc(10); //分配得来得10字节的区域在堆区 p2 = (char *)malloc(20); //分配得来得20字节的区域在堆区 strcpy(p1, \”def\”); //123456{post.content}放在常量区,编译器可能会将它与p3所指向的\”123456\”优化成一块 printf(\”栈空间地址:%p %p\\n\”,&sb,s); printf(\”命令行或环境变量区:%p %p\\n\”,&argc,argv); printf(\”堆区:%p %p\\n\”,p1,p2); printf(\”代码区地址:%p\\n\”,func); printf(\”常量区地址:%p %p\\n\”,p3,\”def\”); printf(\”全局未初始化区:%p %p\\n\”,&gi1,&gi2); printf(\”全局初始化区:%p %p\\n\”,&g1,&g2); system(\”pause\”);}#endif/*栈空间地址:0012FF44 0012FF40命令行或环境变量区:0012FF50 00390F08堆区:00392C08 00392C50代码区地址:0040100F常量区地址:004330D0 004330D0全局未初始化区:0043A4E8 0043A4EC全局初始化区:0043A4DC 0043A4E0*/

C语言内存分布(内核区、堆栈区等)

注意栈区内部的地址,按声明的顺序,地址的增长是从高到低的。

C语言内存分布(内核区、堆栈区等)

C语言内存分布(内核区、堆栈区等)

#include <stdio.h>#include <stdlib.h>//void __stdcall func(int param1,int param2,int param3)void __cdecl func(int param1,int param2,int param3){ int var1=param1; int var2=param2; int var3=param3; printf(\”0x%08x\\n\”,&param1); //打印出各个变量的内存地址 printf(\”0x%08x\\n\”,&param2); printf(\”0x%08x\\n\\n\”,&param3); printf(\”0x%08x\\n\”,&var1); printf(\”0x%08x\\n\”,&var2); printf(\”0x%08x\\n\\n\”,&var3); return;}int main(){ func(1,2,3); system(\”pause\”); return 0;}/*0x0012fef00x0012fef40x0012fef80x0012fee40x0012fee00x0012fedc*/

C语言内存分布(内核区、堆栈区等)

数据内部的存储又是区分大端小端的:

Compaq公司的一部分和Intel的机器(X86平台)一般采用小端。

IBM、Motorola(Power PC), Sun的机器一般采用大端。

当然,这不代表所有情况。有的CPU既能工作于小端, 又能工作于大端, 比如ARM、Alpha、摩托罗拉的PowerPC。具体这类CPU是大端还是小端,应该和具体设置有关。如Power PC支持little-endian字节序,但在默认配置时是big-endian字节序。

一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是Little Endian的。少部分,如MAC OS ,是Big Endian 的。

Little Endian还是BigEndian与操作系统和芯片类型都有关系。

为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?在这里我想说说两种语言。C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用bigendian方式来存储数据。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?

无独有偶,所有网络协议也都是采用bigendian的方式来传输数据的。所以有时我们也会把bigendian方式称之为网络字节序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。

-End-

本文来自网络,不代表汉扬编程立场,转载请注明出处:http://www.hyzlch.com/mianfei/6508.html

C++编程自学宝典:初识C++语言

初学编程,关于编程语言以及最适合他们的编程工具,你知道多少?

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

返回顶部