引入:内存(RAM),ROM,FLASH的概念
对于我们嵌入式而言,我们的开发空间经常是有限的,我们需要更深入理解内存,控制自己代码的内存大小是很有必要的。
一:RAM的定义:
RAM :随机存取存储器(random access memory,RAM)又称作“随机存储器”。
是与CPU直接交换数据的内部存储器,也叫主存(内存)。它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。
在整个程序中凡是需要进行修改的量都存放在内存(RAM)中。(也就是变量)
二:FLASH定义:
FLASH :Flash 存储器(FLASH EEPROM)又称闪存,快闪。它是EEPROM的一种。它结合了ROM和RAM的长处。不仅具备电子可擦除可编辑(EEPROM)的性能,还不会断电丢失数据同时可以快速读取数据。它于EEPROM的最大区别是,FLASH按扇区(block)操作,而EEPROM按照字节操作。FLASH的电路结构较简单,同样容量占芯片面积较小,成本自然比EEPROM低,因此适合用于做程序存储器。
在程序中,一般来说进过const修饰的常量存储在flash中。(也就是常量)
三:ROM定义:
ROM (Read Only Memory)程序存储器
ROM全称Read Only Memory,顾名思义,它是一种只能读出事先所存的数据的固态半导体存储器。ROM中所存数据稳定,一旦存储数据就再也无法将之改变或者删除,断电后所存数据也不会消失。其结构简单,因而常用于存储各种固化程序和数据。
一般rom是程序存储的位置,断电不会丢失数据。
一:变量和常量
一:常量
一:基本定义
常量:一般比较小(只读不写),一般存储到FLASH里面。
//常量的命名
const int i=0;
const int j=0;
//常量一般都保存到flash里面
二:常量存放
常量一般存放到flash中,当较少时也可以被直接存入到内存里面进行读取。
注:当一个常量已经被const修饰,那么在程序里面就不能对其进行修改值了,当我们进行修改的时候,程序会报错。
二:变量(变量一定在内存中占有空间)
一:基本定义
变量:可以不断的进行修改(又读又写),一般存储到内存(RAM)里面。
//变量的命名
int i;//volatile int i
int j;//volatile int i
//变量又全局变量和局部变量的区分
二:变量的存放
变量存放到内存(RAM)中。
当我们定义三个变量会发现
//定义三个变量
volatile int a;
volatile char c;
volatile int arr[4];
他们的地址存放
内存排布:
c 0x2000 000c | 0x2000 000d | 0x2000 000e | 0x2000 000f |
a 0x2000 0008 | 0x2000 0009 | 0x2000 000a | 0x2000 000b |
————————其中一个int类型的变量大小为4个字节,char为一个字节——————————
补充:在读取内存的时候,程序以每次读写四个字节的效率最高,有些硬件甚至只支持一次读四个。所以当一块连续的空间,存放有一个char类型的数据,他后面的三位数据实际上是浪费掉的。
char a; | 浪费 | 浪费 | 浪费 |
我们使用size of函数读取的也是四个字节而不是一个字节。(后面结构体部分还会进行补充)
二:指针
一:基本定义
指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的。
二:指针的大小
指针变量的大小:取决于物理内存的大小,其中32位单片机来说,他的指针变量大小不管是int类型还是char类型它的大小都是4个字节。即指针变量大小不固定。
(不难得出在64位处理器上,指针变量的大小就是16个字节)
在我们经常使用的stm32单片机里面指针变量的大小都是4个字节。
//在同一处理器下,指针变量的大小是一致的
volatile int *;//整型
volatile short *;//短整型
volatile char *;//字符
volatile struct p//结构体
{
} *;
//在stm32平台下,所有的指针变量都是4个字节大小
三:简单的类比
类比:
char c; size of(c) 1
int c; size of(c) 4
int *p; size of(p) 4
char *p; size of(p) 4 只要是指针大小一定是4
int *p; size of(*p) 4
char *p; size of(*p) 1
区别:p是指针变量所以他的大小永远都是4
但是*p 是一个char或者int 类型的量,他的大小就不固定了。
区别:p是指针变量所以他的大小永远都是4
但是*p 是一个char或者int 类型的量,他的大小就不固定了。
三:常用的四个关键字
一:volatile关键字(易怒的也就是别来招惹我)
作用:防止变量被编译器优化,和避免直接走cpu而不调用寄存器
一:防止被程序优化
int main()
{
int i;
i=1;//按照正常的C语言编译,这个i=1实际上是没意义的,最终结果肯定是i=2;
i=2;
}
在编译器运行的时候,这个i=1是无意义的,这个结果会被直接优化掉,如果我们只看结果的话,那么这个结果倒无所谓,但是如果我们需要i=1;这个中间数据来触发一些中断什么的,那么被优化以后程序就会出问题,这个时候我们加上volatile这个关键字就可以避免这个问题。
int main()
{
volatile int i;
i=1;//按照正常的C语言编译,这个i=1实际上是没意义的,最终结果肯定是i=2;
i=2;
}
二:防止cpu不调用寄存器数据
也就是说i的数值变化只经过cpu而不经过内存,这样可以加快程序运行的速度。那为什么我们放着运行速度快的不用呢,还要加volatile这个关键字呢。原因就在于这对普通的软件开发可能不会有什么影响,但是对于嵌入式开发来说,不能及时反馈寄存器的值这是致命的。
二:static关键字(静止的也就是降低变量的作用域)
静态变量static(这样这个变量的工作范围就在这个文件里面,不会影响其他的文件)也就是限制作用域。(原因是如果你重复定义一个变量会报错重复定义)
int ;整个项目都可以调用
static int 只有当前文件夹可以调用。
三:const关键字
本意就是这个变量可以直接放置到flash上面,可以节省一下内存(用来解决内存不够)
当你定义了const 以后这个量就变成了常量,这样程序里面你要是修改他就会报错。
const int i=10;
int main()
{
//i=99;此时就会报错,因为他是常量
}
四:extern关键字
extern 可调用外部变量。,在模块化编程里面让其他模块程序来调用这个变量。
在头文件里面extern 这个变量,另外一个文件#include这个头文件即可。
四:结构体
结构化的好处:程序更加紧凑,具有更强的逻辑.(使用基本的类型创造一种新的类型)。
实例:打印一个学生全部信息。定义一个结构体后面就可以,也就是避免重复造车。
使用基本的类型创造一种新的类型。
struct person
{
int name;
int age;
};
struct cmpany{
char *name;
char worker[100];
}
只有变量才占内存,我们创造出来新的类型,类型不占内存,只有用这些类型定义的变量才会占空间。指针大小永远都是4
注意:按照我们正常的想法来说,应该结构体里面有一个char和一个int,char一个字节,int四个字节正常水平来看这个结构体一大小应该是五个字节二应该是六个字节,但是编译器跑下来他的大小都是八个字节。那么原因是什么呢?
struct person1
{
char name;
int age;
};
struct person1
{
char name;
char a;
int age;
};
这就是我们上文说的有些硬件只支持四位四位的读取,这样的读取效率最高。
在读取内存的时候,程序以每次读写四个字节的效率最高,有些硬件甚至只支持一次读四个。所以当一块连续的空间,存放有一个char类型的数据,他后面的三位数据实际上是浪费掉的。但是如果同时给他几个char类型的数据他又会自动补上去。就是很奇妙。
char a; | 浪费 | 浪费 | 浪费 |
也就是说,当1-4个char他占用的都是四个字节大小,5-8个都是八个字节大小。