嵌入式Linux上的C语言编程实践--第13章 C语言程序的内存布局

合集下载

嵌入式系统C语言编程基础PPT课件

嵌入式系统C语言编程基础PPT课件

精选ppt
小测验?
精选ppt
Quiz 1
• 所有嵌入式系统的主流程最后都进入一个 死循环,怎样用C语言实现一个死循环?
精选ppt
Quiz 2
• while(){….}和do{….}while()有什么区别?
精选ppt
Quiz 3
• 用变量a给出下列定义:
a) 一个整型数 b) 一个指向整型数的指针 c) 一个有10个整型数的的数组 d) 一个有10个指针的数组,该指针是指向一个整型
精选ppt
Quiz 10
• 请评论下面一段程序代码: void test() { char string[10]; char *str = “0123456789”; strcpy(string,str); }
精选ppt
Quiz 11
• 请评论下面一段程序代码: void GetMemory(char *p){ p = (char *)malloc(0x20); } void Test(void){ char *str = NULL; GetMemory(str); strcpy(str,”Hello World!”); printf(str); }
数的
精选ppt
Quiz 4
• 关键字static的作用是什么?
精选ppt
Quiz 5
• 关键字const的作用是什么?
精选ppt
Quiz 6
• 定义一个标准宏MIN ,这个宏输入两个参 数并返回较小的一个。
精选ppt
Quiz 7
• 嵌入式系统中经常要对变量或寄存器进行 位操作。给定一个int型变量a,写两段代码, 第一个将a的bit 3置为1,第二个将a的bit 3 置为0。以上两个操作中,要保持其它位不 变。

C语言操作系统编程进程管理和内存管理

C语言操作系统编程进程管理和内存管理

C语言操作系统编程进程管理和内存管理1. 概述操作系统是计算机系统中最核心的软件之一,它负责管理计算机的硬件资源并提供应用程序运行的环境。

编写操作系统需要掌握底层硬件知识、算法与数据结构以及编程语言。

本文将重点介绍C语言在操作系统编程中的进程管理和内存管理实践。

2. 进程管理2.1 进程与线程的概念在操作系统中,进程是指一个正在运行的程序实例,它具有自己的内存空间、代码、数据和文件等资源。

线程是进程的执行单元,一个进程可以拥有多个线程,它们共享进程的资源。

2.2 进程创建和销毁在C语言中,可以利用操作系统提供的API来创建和销毁进程。

常用的API包括`fork()`、`exec()`和`exit()`等。

`fork()`函数可以创建一个新的进程,`exec()`函数可以用新的程序替换当前进程的代码和数据段,`exit()`函数可以正常或异常地退出进程。

2.3 进程调度进程调度决定了系统中哪个进程在什么时候运行。

C语言通过操作系统提供的API进行进程调度,如`sched_yield()`函数可以让出CPU,`sleep()`函数可以使进程进入休眠状态。

此外,还可以使用多线程编程来实现并发执行。

3. 内存管理3.1 内存模型在操作系统中,内存被划分为多个区域,如代码段、数据段、堆和栈等。

C语言程序的内存布局包括:全局变量、静态变量、堆、栈等。

3.2 动态内存分配动态内存分配是指程序在运行过程中根据需要动态地分配和释放内存。

C语言提供了`malloc()`和`free()`函数来实现动态内存分配。

使用时应注意避免内存泄漏和悬空指针等问题。

3.3 内存保护和地址空间操作系统通过内存保护机制来避免不同进程之间的内存访问冲突。

C语言通过指针操作来访问内存,需要合理地使用指针,并通过操作系统提供的API实现内存保护。

4. 示例代码以下是一个简单的示例代码,演示了C语言操作系统编程中的进程管理和内存管理:```c#include <stdio.h>#include <stdlib.h>int main() {// 创建子进程int pid = fork();if (pid < 0) {printf("进程创建失败\n");exit(1);} else if (pid == 0) {// 子进程执行的代码printf("子进程ID:%d\n", getpid()); printf("父进程ID:%d\n", getppid()); exit(0);} else {// 父进程执行的代码printf("父进程ID:%d\n", getpid()); printf("子进程ID:%d\n", pid);}return 0;}```5. 总结本文介绍了C语言操作系统编程中的进程管理和内存管理。

嵌入式c语言程序设计

嵌入式c语言程序设计

嵌入式c语言程序设计嵌入式C语言程序设计嵌入式C语言程序设计是指在嵌入式系统中使用C语言进行编程的一种技术。

嵌入式系统是指被嵌入到其他设备中的计算机系统,它通常具有特定的功能和任务。

嵌入式C语言程序设计具有高效、灵活、可移植等特点,因此在嵌入式系统开发中得到广泛应用。

一、嵌入式系统概述嵌入式系统广泛应用于各个领域,如消费电子、汽车电子、医疗设备、工业控制等。

嵌入式系统通常由处理器、存储器、输入输出设备和特定功能模块等组成。

与通用计算机系统相比,嵌入式系统的资源有限,因此需要对程序进行精简和优化,以满足系统的实时性和可靠性要求。

二、嵌入式C语言的特点1. 简洁高效:C语言是一种高级语言,具有简洁、高效的特点。

使用C语言可以以较少的代码实现复杂的功能,提高开发效率和系统性能。

2. 可移植性强:C语言是一种可移植性较强的语言。

嵌入式C语言程序可以在不同的嵌入式系统上进行移植,只需做出适当的修改即可。

3. 丰富的库函数支持:C语言提供了丰富的库函数,如字符串处理、数学计算、文件操作等,方便开发人员进行程序设计。

4. 直接访问硬件:嵌入式C语言程序可以直接访问硬件资源,如寄存器、外设等,使得程序可以更加灵活和高效地控制系统。

三、嵌入式C语言程序设计的基本原则1. 软硬件接口设计:嵌入式C语言程序需要与硬件进行交互,因此需要设计合理的软硬件接口,确保程序能够正确地访问硬件资源。

2. 系统资源管理:嵌入式系统的资源有限,因此需要合理地管理系统资源,包括内存、处理器时间、外设等,以满足系统的实时性和可靠性要求。

3. 实时性要求:嵌入式系统通常需要实时响应外部事件,因此嵌入式C语言程序需要按时完成任务,避免出现延迟或死锁等问题。

4. 代码优化:嵌入式系统的资源有限,因此需要对程序进行优化,以减少代码量、提高运行效率和节约资源消耗。

5. 异常处理:嵌入式系统可能会面临各种异常情况,如硬件故障、通信异常等,嵌入式C语言程序需要具备相应的异常处理机制,以保证系统的稳定性和可靠性。

《C语言程序设计》(第2版)苏小红-13章 12

《C语言程序设计》(第2版)苏小红-13章 12
作用
2021/7/31
40/60
struct sample {
short i; char ch; float f; };
union sample {
short i; char ch; float f; };
2021/7/31
共用体
【例12.8】
printf("%d\n", sizeof(struct sample));
Before function call:1999/04/23 After function call:2000/05/22
指针作函数形参 实参必须为地址值
2021/7/31
33/60
struct date
{
int year; int month;
结构体变量
int day; };
作函数返回值
struct date Func(struct date p)
2021/7/31
【例12.3】利用 结构体数组计 算每个学生的 平均分
25/60
结构体指针的定义和初始化
如何定义指向结构体变量的指针?
pt STUDENT stu1; STUDENT *pt; pt = &stu1;
等价于
STUDENT *pt = &stu1;
stu1 成员1 成员2 成员3 成员4
i ch
f
8个字节
printf("%d\n", sizeof(union sample));
0x0037b00
cfih
4个字节 41/60
共用体
sizeof(union number)取决于占空间最多的那个成员 变量
同一内存单元在每一瞬时只能存放其中一种类型的成员 起作用的成员是最后一次存放的成员,不能作为函数参数 不能进行比较操作,只能对第一个成员初始化

c语言的内存结构

c语言的内存结构

c语言的内存结构C语言是一种高级编程语言,但实际上在计算机中运行时,C语言程序会被编译成可执行文件,然后在计算机内存中运行。

因此,了解C 语言的内存结构对于理解C程序的运行及性能优化至关重要。

C语言的内存结构主要可以分为以下几个部分:栈(Stack)、堆(Heap)、全局内存(Global Memory)和代码区(Code Segment)。

首先是栈(Stack),栈是一种自动分配和释放内存的数据结构。

它用于存储局部变量、函数参数和函数调用信息等。

栈的特点是后进先出(LIFO),也就是最后进入的数据最先被释放。

栈的大小在程序运行时是固定的,一般由编译器设置。

栈的操作速度较快,但内存空间有限。

其次是堆(Heap),堆是一种动态分配和释放内存的数据结构。

它用于存储动态分配的变量、数据结构和对象等。

堆的大小一般由操作系统管理,并且可以在运行时进行动态扩展。

堆的操作相对较慢,因为需要手动分配和释放内存,并且容易产生内存碎片。

全局内存(Global Memory)是用于存储全局变量和静态变量的区域。

全局变量在程序的生命周期内都存在,并且可以在多个函数之间共享。

静态变量作用于其所在的函数内,但是生命周期与全局变量相同。

全局内存由编译器进行分配和管理。

代码区(Code Segment)存储了程序的指令集合,它是只读的。

在程序运行时,代码区的指令会被一条一条地执行。

代码区的大小由编译器决定,并且在程序执行过程中不能修改。

此外,C语言还具有特殊的内存区域,如常量区和字符串常量区。

常量区用于存储常量数据,如字符串常量和全局常量等。

常量区的数据是只读的,且在程序的整个生命周期内存在。

字符串常量区是常量区的一个子区域,用于存储字符串常量。

在C语言中,内存分配和释放是程序员的责任。

通过使用malloc和free等函数,程序员可以在堆中动态地分配和释放内存,从而灵活地管理程序的内存使用。

不过,应当注意避免内存泄漏和野指针等问题,以免出现内存错误和性能问题。

嵌入式系统中的内存管理

嵌入式系统中的内存管理

嵌入式系统中的内存管理在嵌入式系统中,内存管理是一个至关重要的问题。

嵌入式系统通常运行在有限的资源和功耗的环境中,因此合理而高效地管理内存资源是确保系统性能和稳定性的关键所在。

本文将探讨嵌入式系统中的内存管理策略和技术,并提供一些实用的建议。

一、静态内存管理静态内存管理是嵌入式系统中常用的一种内存管理方法。

在此方法中,内存的分配工作在编译时就完成了。

静态内存管理适用于那些内存需求在编译时可以确定的情况,例如固定大小的数据结构或全局变量。

这种方法的好处是简单且效率高,但是不适用于动态内存需求频繁变化的情况。

二、动态内存管理动态内存管理是指在程序运行时通过动态分配和释放内存来满足程序的需求。

在嵌入式系统中,常用的动态内存管理方式是使用堆来进行内存分配。

堆是由操作系统或者嵌入式系统的运行时库所管理的一块内存空间,程序可以通过申请和释放堆内存来满足其动态内存需求。

在使用动态内存管理的过程中,需要注意以下几点:1. 内存泄漏的风险动态内存管理需要程序员手动申请和释放内存,如果未正确释放已分配的内存,就会导致内存泄漏的问题。

内存泄漏会导致系统性能下降和稳定性问题,并可能最终导致系统崩溃。

因此,在使用动态内存管理时,务必要注意正确释放已分配的内存空间,避免内存泄漏的发生。

2. 内存碎片的处理动态内存分配往往会产生内存碎片问题。

内存碎片是指内存中存在一些空闲但不连续的小块内存,这会导致内存利用率降低。

为了避免内存碎片问题,可以采用内存池技术,将内存按照固定大小的块进行划分,并预先分配给程序使用。

这样可以最大程度地减少内存碎片,提高内存利用率。

3. 内存分配算法的选择在动态内存管理中,选择合适的内存分配算法也非常重要。

常见的内存分配算法包括First Fit、Best Fit和Worst Fit等。

不同的算法有着不同的优缺点,因此在选择时需要根据具体情况进行权衡。

例如,First Fit算法简单高效,但容易产生内存碎片;而Best Fit算法可以最小化碎片问题,但是分配效率较低。

《C语言程序设计》教案(清华谭浩强)

《C语言程序设计》教案(清华谭浩强)

《C语言程序设计》教案(清华谭浩强)第一章:C语言概述1.1 课程介绍介绍C语言的历史和发展解释C语言的特点和应用范围强调学习C语言的重要性和目的1.2 C语言的基本概念解释编程语言和编译器的概念介绍C语言的基本数据类型和变量讲解C语言的语法结构和程序结构1.3 C语言的编译过程解释编译器的角色和功能介绍编译过程中的预处理、编译、汇编和步骤强调编译过程中产生的文件和它们的作用第二章:基本数据类型和运算符2.1 基本数据类型介绍整型、浮点型、字符型和布尔型的概念和用法解释不同数据类型的存储方式和大小强调数据类型的选择和使用场景2.2 变量和常量解释变量的概念和作用介绍变量的声明和初始化方法讲解常量的概念和用法2.3 运算符介绍算术运算符、关系运算符和逻辑运算符的概念和用法解释赋值运算符和条件运算符的作用强调不同运算符的优先级和使用规则第三章:控制语句3.1 条件语句介绍if语句的语法和用法讲解switch语句的概念和用法强调条件语句的选择和嵌套使用3.2 循环语句介绍for循环、while循环和do-while循环的概念和用法解释循环控制语句如break和continue的作用强调循环条件的设置和循环次数的控制3.3 跳转语句介绍goto语句的概念和用法讲解label标签的作用和跳转规则强调跳转语句的使用场景和可能导致的问题第四章:函数和指针4.1 函数的基本概念介绍函数的定义和声明讲解函数的参数传递和返回值强调函数的命名规则和命名规范4.2 指针的概念和用法解释指针的概念和作用介绍指针的声明和初始化方法讲解指针的赋值和指针运算4.3 指针和数组介绍数组的概念和用法解释指针和数组的关系强调指针在数组操作中的应用第五章:结构体和文件操作5.1 结构体的概念和用法介绍结构体的定义和声明讲解结构体的成员访问和内存布局强调结构体在数据组织中的应用5.2 文件操作的基本概念解释文件的概念和文件操作的重要性介绍文件打开、读写、关闭等操作的方法强调文件操作中的错误处理和文件指针的管理第六章:动态内存分配6.1 动态内存分配的概念介绍动态内存分配的原因和必要性解释malloc、calloc和realloc函数的作用和用法强调动态内存分配的注意事项和错误处理6.2 链表的概念和用法介绍链表的定义和结构讲解链表的创建、插入、删除和遍历操作强调链表的优势和应用场景6.3 动态内存分配的应用实例通过实例演示动态内存分配在实际编程中的应用讲解内存泄漏和内存溢出的概念强调编写高效和安全的程序的重要性第七章:字符串处理7.1 字符串的基本概念介绍字符串的定义和表示方法解释字符串的长度和字符串的结束标志强调字符串与数组的区别和联系7.2 字符串的常用函数介绍字符串的输入输出函数如printf和scanf 讲解字符串的拷贝、连接、比较等操作函数强调字符串处理函数的使用和注意事项7.3 字符串处理的应用实例通过实例演示字符串处理在实际编程中的应用讲解字符串排序、查找和替换等操作强调字符串处理在文本分析和数据处理中的应用第八章:标准库函数8.1 标准输入输出库函数介绍标准输入输出库stdio.h中的常用函数讲解文件读写、数据转换等函数的用法和功能强调标准库函数的使用场景和注意事项8.2 字符串处理库函数介绍字符串处理库string.h中的常用函数讲解字符串比较、查找和替换等函数的用法和功能强调字符串处理库函数的使用和与其他库函数的配合8.3 数学计算库函数介绍数学计算库math.h中的常用函数讲解数学运算、三角函数和指数函数等函数的用法和功能强调数学计算库函数在数学计算和科学计算中的应用第九章:并发编程和同步机制9.1 并发编程的基本概念介绍并发编程的定义和目的解释进程和线程的概念和关系强调并发编程的优势和挑战9.2 并发编程的同步机制介绍互斥锁、条件变量和信号量等同步机制的原理和用法讲解同步机制在多线程编程中的应用和注意事项强调同步机制在避免竞态条件和数据一致性中的重要性9.3 并发编程的应用实例通过实例演示并发编程在实际应用中的优势和挑战讲解多线程的创建、同步和通信等操作强调并发编程在多任务处理和性能优化中的应用第十章:C语言编程实践10.1 编程实践的重要性强调编程实践在学习和掌握C语言中的重要性解释编程实践对于提高编程能力和解决问题的作用强调编程实践中的代码质量和编程规范10.2 编程实践的项目和案例介绍常见的编程实践项目和案例讲解实际编程中的问题解决方法和技巧强调编程实践中的调试和测试的重要性10.3 编程实践的资源和工具介绍编程实践中的常用工具和环境讲解集成开发环境(IDE)的使用和代码管理强调编程实践中的团队合作和代码分享的重要性重点和难点解析重点环节1:C语言的基本概念和特点需要重点关注C语言的历史和发展,以及其特点和应用范围。

进程的内存空间布局

进程的内存空间布局

进程的内存空间布局进程的内存布局在结构上是有规律的,具体来说对于 linux 系统上的进程,其内存空间⼀般可以粗略地分为以下⼏⼤段【1】,从⾼内存到低内存排列:1、内核态内存空间,其⼤⼩⼀般⽐较固定(可以编译时调整),但 32 位系统和 64 位系统的值不⼀样。

2、⽤户态的堆栈,⼤⼩不固定,可以⽤ ulimit -s 进⾏调整,默认⼀般为 8M,从⾼地址向低地址增长。

3、mmap 区域,进程茫茫内存空间⾥的主要部分,既可以从⾼地址到低地址延伸(所谓 flexible layout),也可以从低到⾼延伸(所谓 legacy layout),看进程具体情况【2】【3】。

4、brk 区域,紧邻数据段(甚⾄贴着),从低位向⾼位伸展,但它的⼤⼩主要取决于 mmap 如何增长,⼀般来说,即使是 32 位的进程以传统⽅式延伸,也有差不多 1 GB 的空间(准确地说是 TASK_SIZE/3 - 代码段数据段,参看 arch/x86/include/asm/processor.h ⾥的定义)【4】5、数据段,主要是进程⾥初始化和未初始化的全局数据总和,当然还有编译器⽣成⼀些辅助数据结构等等),⼤⼩取决于具体进程,其位置紧贴着代码段。

6、代码段,主要是进程的指令,包括⽤户代码和编译器⽣成的辅助代码,其⼤⼩取决于具体程序,但起始位置根据 32 位还是 64 位⼀般固定(-fPIC, -fPIE等除外【5】)。

以上各段(除了代码段数据段)其起始位置根据系统是否起⽤ randomize_va_space ⼀般稍有变化,各段之间因此可能有随机⼤⼩的间隔,千⾔万语不如⼀幅图(x86-32位下):32位下bash进程的⽰例:【1】【2】understanding the linux kernel, page 819, flexible memory region layout: 【3】【4】【5】。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2
13.1 C语言程序的存储区域
由C语言源程序形成可执行程序(二进制文件),需要经 过编译、汇编、连接三个阶段
编译:根据C源程序生成汇编程序 汇编:根据汇编程序翻译成二进制机器代码 连接:将各个源文件生成的二进制机器代码组合成一个文件。
C源文件经过编译-汇编-连接后,将形成一个统一的文 件,它由代码段(Code/Text)、只读数据段(RO data) 和读写数据段(RW data)三部分组成。在运行时又会产 生另外三部分:未初始化数据段(BSS)、堆(Heap)和 栈(Stack)。各个部分代表了不同的存储区域。
用const定义“常量”时必须初始化。
13.3
可执行程序的连接
13.3.1 可执行程序的组成
目标文件(.o)的主要组成部分包含代码段、只读数 据段和读写数据段三个段。未初始化数据段、堆和栈 不会占用目标文件的空间。 C语言可执行程序是由各个目标文件经过连接生成。 其主体部分依然是代码段、只读数据段和读写数据段 ,这三个段由各个目标文件(.o)经过“组合”而成。 C语言目标文件到可执行程序的连接如图13-2所示。 由连接器生成的可执行程序包含了各个目标文件的各 个段的内容,并且会附加可执行程序的头信息。在可 执行程序中,各个目标文件的代码段、只读数据段、 读写数据段经过了重新的排列组合。
在C语言中,读写数据段和未初始化数据段中 包含了:
整个程序的全局变量 单个文件内使用的全局变量(函数外部用static修饰 的) 局部静态变量(函数内部用static修饰的)。
13.3.2 各个目标文件的关系
编译时:
编译时只进行函数调用的语法检查。 只要被调用的函数有声明(不需要定义实现),编译 器就可以成功处理。
链接时:
链接时,链接器将各个可执行程序的代码段组合到一 起,有函数调用的地方还需要找到真正的函数定义才 可以完成链接。 链接器会根据实际情况修改编译生成的机器代码,完 成正确的跳转。
1.代码段(code或text)
代码段由程序中可执行的机器代码组成。
2.只读数据段(RO data)
只读数据段是程序中使用的一些不能被更改的数据, 可以用查表的方式使用这些数据。 程序中由const定义的常量、其他的字符串常量将位于 此段中。 由于这些数据不能被更改,因此,这些数据在嵌 入式应用中需要放置在只读存储器中。
第五部分 在嵌入式环境 下的C语言编程
第13章 C语言程序的内存布局 第14章 嵌入式C语言常用语法 第15章 嵌入式C语言编程的技巧
第13章 C语言程序的内存布局
本章介绍C语言程序的内存布局,包括连接过 程中目标程序各个段的组成和运行过程中各个 段加载的情况 主要内容:
C语言程序在内存中各个段的组成 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式
5.堆(heap)
堆内存只在程序运行时出现,通常由程序员分配和 释放。在有操作系统时,如果程序没有释放,操作 系统可能在程序结束后回收内存。
6.栈(stack)
栈内存只在程序运行时出现,在函数内部使用的自 动变量、函数的参数以及返回值将使用栈空间。 由编译器自动分配和释放。
代码段、只读数据段、读写数据段、未初始化 数据段属于静态区域 堆和栈属于动态区域 代码段、只读数据段和读写数据段将在连接后 产生。 未初始化数据段将在程序初始化时开辟。 堆和栈将在程序的运行中分配和释放。
关于const
在C语言中,const是限定一个变量不允许被改变,而不 是真正定义了一个常量,只是定义了一个只读变量。 如:const int N=20;int x[N]是错误的。 使用const在一定程度上可以提高程序的安全性和可靠性 ,另外,在观看别人代码的时候,清晰理解const所起的 作用,对理解对方的程序也有一些帮助。如对函数的参 数加上const限定,可防止参数被无意修改。 理解const的用法
3.读写数据段(RW data)
目标文件中可读可写的数据区,有时也称为已 初始化数据段。 与代码段、只读数据段同属程序的静态区域, 但读写数据段具有可写的特点。 以下变量将放入读写数据段:
已初始化全局(静态)变量 已初始化局部静态变量
放入读写数据段中的变量必须是在程序中进行 初始化了的变量,如果没有初始化,将被放在 未初始化数据段中。
示例1
const char ro[]={"this is readonly data"}; /* 只读数据段 */ static char rw1[]={"this is global readwrite data"}; /* 已初始化读写数据段 */ char bss_1[100]; /* 未初始化数据段 */ const char * ptrconst = "constant data";
可执行程序 目标文件1 Code1 (代码段1) RO Data (只读数据段1) RW Data (读写数据段1) 程序头部 Code1 Code2 …… RO data1 目标文件2 Code1 (代码段2) RO Data (只读数据段2) RW Data (读写数据段2) RO data2 …… RW data1 RW data2 …… 链接过程 读写数 据段 只读数 据段 代码段
char *p1; char *p2 = “123456”;
/* p1在栈上,占用4个字节 */ /* “123456”放置在只读数据存储区 ,占7字节 */ /* p2在栈上,p2指向的内容不能更改。 */ static char rw2[]={"this is local readwrite data"}; /* 局部已初始化读写数据段 */ static char bss_2[100]; /* 局部未初始化数据段 */ static int c = 0; /* 全局(静态)初始化区 */ p1= (char *)malloc(10*sizeof(char)); /* 分配的内存区域在堆区。 */ strcpy(p1, "xxxx"); /* "xxxx"放置在只读数据存储区,占5字节 */ free(p1); /* 使用free释放p1所指向的内存 */ return 0; }
已初始化读写数据段(RW data)
程序中声明的已初始化的全局变量或静态局部变量, 在程序执行时需要位于可读写的内存区域内,以供程 序运行时读写。
4.未初始化数据段(BSS--Block Start by Symbol)
未初始化数据是在程序中声明、但没有被初始化的 全局变量或局部静态变量。 这些变量在程序运行前不需要占用存储器空间。
从上例可知:
只读数据段:包括了程序中定义的const型数据(如 const char ro[])、程序中的字符串常量(如“constant data”)。 读写数据段:包括了已初始化了的全局变量(如static char rw[])和局部静态变量(如static char rw2[]),这 些变量属于静态区,但均可进行读写。 未初始化数据段:包括了未初始化的全局变量和静态局 部变量。 栈:函数内部定义的自动变量,形参、返回值在栈上。 堆:用malloc,calloc,realloc等内存分配函数所分配的 内存空间在堆上
C语言程序的组成分为映像和运行时两种状态:
映像--静态结构:可执行程序加载到内存前的状态 。此时,文件中将只包含代码段、只读数据段和读写 数据段。 在程序加载到内存后、运行之前,将动态生成未初始 化数据段。 在程序的运行过程中将动态生成堆和栈区域。
在静态的映像文件中,各个部分称之为节( Section),而在运行时的各个部分称之为段( Segment)。
在C语言中,变量定义与段的对应关系:
1.在函数体中定义的自动变量是在栈上,不需要在程序中进 行管理,由编译器处理;在函数体中定义的静态变量是在全 局区(静态区):被初始化了的在读写数据段,未初始化的 在未初始化数据段。 2.用malloc,calloc,realloc等内存分配函数所分配的内存空 间在堆上,程序必须保证在使用后用free释放,否则会发生内 存泄漏。 3.所有函数体外定义的是全局变量,加了static修饰符后的变 量不管在函数内部或者外部都存放在全局区(静态区):被 初始化了的在读写数据段,未初始化的在未初始化数据段。 4.使用const定义的变量将放于程序的只读数据段。
图13-2 C语言目标文件到可执行程序的连接
从C语言使用的角度,读写数据段和未初始化 数据段都是可读写的。 在目标文件(*.o)中未初始化数据段和读写数 据段的区别在于:读写数据段占用目标文件的 容量,而未初始化数据段只是一个标识,不需 要占用实际的空间。 可执行程序中读写数据段的大小会等于各个目 标文件读写数据段之和。对于未初始化数据段 上的变量,连接器也将各个目标文件中的信息 相加得到可执行程序的未初始化段的大小,但 是这个段同样不会占用可执行文件的空间。
const int nValue; //nValue是const const char *pContent; //*pContent是const, pContent可变 const (char *) pContent; //pContent是const,*pContent可变 char* const pContent; //pContent是const,*pContent可变 const char* const pContent; //pContent和*pContent都是const
13.2.2 程序中段的使用
C语言程序中的全局区(静态区),实际对应 着下述几个段:
只读数据段:RO Data 读写数据段:RW Data 未初始化数据段:BSS Data
一般来说,未初始化的全局变量在未初始化数 据段,如果该变量有初始化则是在已初始化数 据段(RW Data),加上const修饰符将放置在 只读数据段(RO Data)。
相关文档
最新文档