当涉及到嵌入式系统或者微控制器的程序大小时,通常会涉及到不同类型的数据以及它们在内存中的存储方式。这些指标对于程序员和系统设计者来说非常重要,因为它们有助于了解程序在特定硬件环境下的内存使用情况。
Code:指的是程序代码的总大小,通常存储在FLASH等非易失性存储器中,用于存储程序的执行代码。在这个例子中,代码大小为46286字节。
RO-data:指只读数据,包括程序中的常量数据和只读变量等,它们在程序运行期间不会被修改。这些数据通常存储在FLASH等存储器中。在这个例子中,只读数据大小为1698字节。
RW-data:指读写数据,即在程序运行期间可以修改的数据,通常存储在RAM中。在这个例子中,读写数据大小为560字节。
ZI-data:指零初始化数据,这部分数据在程序加载时会被初始化为零值或空值。它们通常存储在RAM中。在这个例子中,零初始化数据大小为39960字节。
这些数据大小可以帮助开发者了解程序在存储器中的分布情况,有助于优化程序以减少内存占用,并确保程序在给定的硬件环境下正常运行。优化代码大小和内存使用可以提高系统性能,并确保在资源受限的嵌入式系统中有效地运行。
eg:
256K Flash >= Code(程序代码) + RO-data(常量和只读变量)
64K SRAM >= RW-data(可以修改的数据,变量) + ZI-data(初始化为0,null的变量)
常量和只读变量在概念上有些微妙的区别,尽管它们都表示在程序运行期间值不会改变的数据,但在C语言中,这两个概念有着不同的实现方式和使用方式:
常量(Constants)
#define 或 const 声明的值:常量是指在程序中一经定义后,其值在整个程序运行期间都不会改变的数据。可以使用 #define 预处理指令或 const 关键字来定义常量。
文本替换或编译时计算:#define 创建的常量是在编译器预处理阶段进行简单的文本替换,而 const 声明的常量会被编译器视为一个具有确定值的变量。
全局替换:#define 常量是全局替换,而 const 常量在编译器中可能会有一些内存空间。
不具备类型:#define 常量通常不具有特定的类型信息,而 const 常量会根据其声明的类型而被编译器识别。
常量是在程序执行过程中其值不能改变的量。在C语言中,有两种方式定义常量:
使用 #define 预处理指令:通过 #define 定义常量,这种常量在程序中会被编译器进行简单的文本替换。例如:
#define PI 3.14159
这里的 PI 被定义为常量,其值为3.14159。在程序中所有出现 PI 的地方都会被替换为 3.14159。
只读变量(Read-only Variables)
使用 const 关键字声明:只读变量是使用 const 关键字声明的变量,它们在定义后不可再修改其值。
变量性质:尽管在概念上看起来像常量,但只读变量本质上仍然是变量,占用内存空间,而且具有特定的类型信息。
更多类型检查:由于是变量,只读变量拥有更多的类型信息和编译时检查,因此更安全。
在实践中,常量和只读变量的选择取决于程序的需要。常量适用于那些在编译时就已经确定并且在整个程序中不会改变的值,而只读变量则更适合表示在程序运行时期间不能修改的值,但需要更多类型检查和更精确的定义。
“只读变量”通常指的是在程序运行时其值不能被修改的变量。在C语言中,通过使用关键字 const 可以创建只读变量。这样的变量一经赋值就不能被修改。
const int readOnlyVar = 10;
在上面的例子中,readOnlyVar 被声明为一个只读变量,它的值被初始化为10,并且在程序的其余部分不能再被修改。这种变量通常被用于存储程序中的常量值或者一些在程序执行期间不应该改变的数据。
什么是RW-data(Read-Write Data)
RW-data(Read-Write Data)是指在程序执行期间可以读取和写入的数据段。这些数据通常存储在RAM(随机存取存储器)中,并且可以在程序的执行过程中进行读写操作。
在C语言中,包括全局变量、静态变量和局部变量在内的大部分变量都属于RW-data。这些变量的内存空间在程序运行时被分配,可以进行读写操作,其值可以随着程序的执行而改变。
例如:
int globalVar=3; // 全局变量,属于RW-data,可以被读取和写入
void someFunction() {
static int staticVar=4; // 静态变量,属于RW-data,可以被读取和写入
int localVar=5; // 局部变量,也存在于堆栈中,属于RW-data,可以被读取和写入
// ...
}
在这个例子中,globalVar 是一个全局变量,staticVar 是一个静态变量,localVar 是一个局部变量,它们都属于RW-data。这些变量的值可以在程序运行期间被读取和修改。RW-data中的数据是可变的,程序可以在执行过程中对这些变量进行读写操作。
什么是ZI-data
在程序运行期间,ZI(Zero-Initialized)数据段用于存储在程序加载时被初始化为零值或空值的变量。这些变量在程序开始执行前就被初始化,因此称为“零初始化”数据。
在C语言中,全局范围内声明的静态变量(或全局变量)如果没有显式初始化,会被默认初始化为零值(0 或 NULL,具体取决于变量的类型)。这些变量所占用的存储空间在程序启动时会被分配,并且初始值会被设为零。
int globalVar; // 全局范围内声明的int类型变量,会被初始化为0(ZI-data)
在上述例子中,globalVar 是一个全局变量,如果没有被显式初始化,它将会被初始化为零值,即ZI-data。ZI-data在程序加载时被操作系统或加载器初始化,这确保了这些变量在程序启动时具有确定的初始状态。
ZI-data通常存储在RAM的BSS(Block Started by Symbol)段中,这个段在程序加载时会被操作系统或加载器清零并分配内存。这个段中的变量在程序运行期间可以被修改,但它们在程序开始执行前已经具有默认的零值。
区别:
在典型的C语言中,全局变量(比如 int globalVar)既可以属于RW-data(可读写数据),也可以属于ZI-data(零初始化数据),这取决于变量是否在定义时被显式地初始化。
如果全局变量在定义时没有被显式地初始化,则它将被默认认为是ZI-data,即在程序加载时将会被初始化为零值。
如果全局变量在定义时被显式地初始化了(例如 int globalVar = 0;),则它不再属于ZI-data,而是具有明确的初始化值,即使这个值是零。在这种情况下,它仍然属于RW-data,可以被读取和写入。
下面是一个例子:
int globalVar1; // 没有显式初始化,默认属于ZI-data,会被初始化为零值
int globalVar2 = 10; // 显式初始化为非零值,属于RW-data,初始值为10
void someFunction() {
static int staticVar; // 没有显式初始化,默认属于ZI-data,会被初始化为零值
// ...
}
总的来说,全局变量的归类取决于其是否被显式地初始化。如果没有显式初始化,它们会被认为是ZI-data,会在程序加载时被初始化为零值。如果显式初始化了,它们将是具有明确初始值的RW-data。