关于变量的存放位置(数据段、代码段、用户堆栈段)

本文深入讲解了程序内存分配中的堆和栈的区别,包括它们的申请方式、系统响应、大小限制、存取效率等方面的知识,并通过具体例子进行了说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

from:http://bbs.chinaunix.net/thread-1032894-1-1.html


int total;               //外部变量,未初始化.存放在bss段

int main(int argc,char **argv)
{
int a;           //自动变量. 栈
int aa=10;  //自动变量. 栈

static b;             //静态变量,未初始化.存放在bss段

int func(int);

...
if (aa==10)           
   {
     int temp;        //局部变量.栈
     ...
   }
func(aa);
...
}


int func(int t)     //形参. 栈
{
int a;         //自动变量. 栈
...
}


from:http://bbs.youkuaiyun.com/topics/380059897


堆和栈的区别

一、预备知识—程序的内存分配

一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

二、例子程序

这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{    
     int b; 栈
     char s[] = "abc"; 栈
     char *p2; 栈
     char *p3 = "123456"; 123456\0在常量区,p3在栈上。
     static int c =0; 全局(静态)初始化区
     p1 = (char *)malloc(10);
     p2 = (char *)malloc(20);
     分配得来得10和20字节的区域就在堆区。
     strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}

二、堆和栈的理论知识

2.1 申请方式
stack:由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:需要程序员自己申请,并指明大小,在c中malloc函数如p1 = (char *)malloc(10);在C++中用new运算符如p2 = (char *)malloc(10);但是注意p1、p2本身是在栈中的

2.2申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

2.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活

2.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6 存取效率的比较
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;而bbbbbbbbbbb是在编译时就确定的;但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:

#include
void main()
{    
     char a = 1;     
     char c[] = "1234567890";     
     char *p ="1234567890";    
     a = c[1];     
     a = p[1];     
     return;     
}

对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

2.7小结:
堆和栈的区别可以用如下的比喻来看出:使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。 使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
堆和栈的区别主要分:
操作系统方面的堆和栈,如上面说的那些,不多说了。还有就是数据结构方面的堆和栈,这些都是不同的概念。这里的堆实际上指的就是(满足堆性质的)优先队列的一种数据结构,第 1个元素有最高的优先权;栈实际上就是满足先进后出的性质的数学或数据结构。虽然堆栈,堆栈的说法是连起来叫,但是他们还是有很大区别的,连着叫只是由于历史的原因。

<think>首先,用户的问题是:“我想了解C语言中变量数据段的存储方式 请问C语言 变量如何存储在数据段”。这基于之前的引用,我需要参考那些引用。 回顾引用内容: - 引用[1]:提到变量a存储在内存中,但具体位置未指定。 - 引用[2]:解释了BSS段和.data段。BSS段用于初始化为0或未初始化的全局变量,.data段用于初始化为非零的全局变量。 - 引用[3]:静态生存期的变量在.rodata、.data或.bss段。 - 引用[4]:static变量在.data或.bss中分配空间;malloc的变量在堆中;局部变量在栈中。 用户特别询问“变量如何存储在数据段”,所以我需要专注于数据段(包括.data和.bss段),因为数据段通常指.data和.bss。 关键点: - **.data段**:存储初始化为非零值的全局变量和静态变量。 - **.bss段**:存储初始化为0或未初始化的全局变量和静态变量(未初始化时默认为0)。 - 数据段是程序的一部分,在程序加载时分配内存。 回答结构: 1. **介绍数据段**:解释什么是数据段,包括.data和.bss。 2. **变量类型**:哪些变量存储在数据段?全局变量、静态变量。 3. **存储方式**:如何存储?在程序启动时分配内存,初始化值。 4. **示例**:提供简单的C代码示例来展示。 5. **注意事项**:区分堆、栈等。 6. **生成相关问题**:按照指令,在最后添加相关问题。 使用LaTeX格式: - 行内数学表达式用$...$,如变量名。 - 独立公式用$$...$$,但这里可能不需要复杂公式。 - 所有内容用中文。 确保回答真实可靠:基于C语言标准内存模型。 步骤: 1. **开头直接回答问题**:概述变量数据段的存储。 2. **详细解释**: - 定义数据段。 - 区分.data和.bss。 - 变量存储位置:全局变量、静态变量。 - 初始化过程。 3. **添加代码示例**:用C代码展示。 4. **结尾添加引用标识**:自然地引用参考。 5. **生成相关问题**:在最后添加。 相关问题想法: 1. 如何优化数据段的使用? 2. 数据段的大小如何影响程序性能? 3. 数据段与堆栈的区别? 4. 在嵌入式系统中数据段的管理? 最终输出格式: - 回答部分。 - §§相关问题§§部分。</think>### C语言变量数据段的存储方式 在C语言中,变量存储在数据段的方式取决于变量的类型、作用域和初始化状态。数据段是程序内存布局的一部分,通常包括`.data`段和`.bss`段(有时统称为数据段),它们在程序加载时由操作系统分配内存。以下我将逐步解释变量如何存储在数据段中,确保内容清晰可靠。 #### 1. **数据段的定义与组成** - **数据段的作用**:数据段用于存储全局变量和静态变量(包括全局静态变量和局部静态变量),这些变量在程序的整个生命周期内存在。数据段分为两个子部分: - **`.data`段**:存储初始化为**非零值**的全局变量和静态变量。例如,`int global_var = 42;` 会被存储在`.data`段。 - **`.bss`段**:存储初始化为**0**或**未显式初始化**(默认为0)的全局变量和静态变量。例如,`int global_zero;` 或 `static int static_var = 0;` 会被存储在`.bss`段。 - **为什么分两个段?** 这主要是为了优化内存使用:`.bss`段不存储实际初始值(因为全为0),只记录大小,从而减少可执行文件体积[^2][^3]。 #### 2. **变量如何存储在数据段** - **存储机制**: - 当程序启动时,操作系统根据编译信息为`.data`和`.bss`段分配固定大小的内存块。 - `.data`段:变量初始值直接嵌入可执行文件,加载时复制到内存。 - `.bss`段:变量初始值全为0,加载时由系统快速清零分配的内存区域。 - 存储方式是**连续内存块**,变量按声明顺序排列,地址由链接器确定。 - **哪些变量存储在数据段?** - **全局变量**:在函数外部定义的变量。例如: ```c int global_data = 10; // 存储在.data段 int global_bss; // 存储在.bss段(默认为0) ``` - **静态变量**:使用`static`关键字声明的变量,无论全局还是局部。例如: ```c static int static_data = 20; // 存储在.data段 void func() { static int static_bss; // 存储在.bss段(默认为0) } ``` - **不存储在数据段变量**:局部变量(非静态)存储在栈(stack),动态分配的变量(如`malloc`)存储在堆(heap)[^2][^3][^4]。 - **初始化过程**: - `.data`段变量:编译时,初始值写入可执行文件;运行时,直接加载到内存。 - `.bss`段变量:编译时,只记录大小;运行时,系统分配内存并初始化为0。 - 示例:假设变量`int a = 5;`,其值5存储在可执行文件的`.data`节,加载后映射到物理内存地址如`0x1000`。 #### 3. **代码示例与内存布局** 以下C代码演示变量数据段的存储: ```c #include <stdio.h> int global_data = 1; // 存储在.data段(初始化为非零) int global_bss; // 存储在.bss段(未初始化,默认为0) static int static_data = 2; // 存储在.data段 static int static_bss; // 存储在.bss段 int main() { static int local_static = 0; // 存储在.bss段(初始化为0) int local_stack = 3; // 存储在栈中,不在数据段 printf("global_data: %d\n", global_data); return 0; } ``` - **内存布局说明**: - `.data`段大小:包含`global_data`和`static_data`(各占4字节,假设`int`为4字节)。 - `.bss`段大小:包含`global_bss`、`static_bss`和`local_static`(总大小由链接器计算)。 - 使用工具如`size`命令(Linux)可查看段大小:`.text`(代码段)、`.data`、`.bss`[^2][^3]。 #### 4. **注意事项与优化** - **性能影响**:数据段变量访问速度快(地址固定),但大小固定,可能导致可执行文件膨胀。未初始化的全局变量放`.bss`段可节省磁盘空间[^2]。 - **安全性**:数据段变量在程序启动后地址不变,易被攻击者利用(如缓冲区溢出),需谨慎使用。 - **与其它段的区别**: - **栈(stack)**:存储局部变量,函数调用时动态分配。 - **堆(heap)**:存储`malloc`分配的变量,手动管理。 - **代码段(.text)**:存储程序指令[^4]。 - 实际存储位置取决于编译器和系统,但标准C规范定义了此模型[^3][^4]。 通过以上解释,C语言变量数据段的存储方式主要基于其类型和初始化状态,确保高效内存管理。如果您有特定场景(如嵌入式系统),可进一步探讨优化策略[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值