1、程序和内存
程序:数据+算法
内存的本质就是存储代码和数据的
数据和代码的存储方式不同,可分为冯诺依曼结构和哈佛结构
冯诺依曼结构:程序和数据存储在同一个存储器,二者共用一条传输总线
哈佛结构:将程序和数据分开存储,指令和数据存取可同时进行
单片机中将变量数据等存放在SRAM中,将程序存储到Flash中,常量通常存储在Flash中
内存管理
系统角度
无OS时:程序直接操作内存,编程这自己计算和安排内存,属于静态内存分配
有OS时:
静态内存分配:通过一些操作系统提供的接口分配内存
动态内存分配:程序运行时,需要随时分配,不需要时随时释放
语言角度
汇编语言:没有内存管理,直接操作内存地址
C语言:编译器管理内存,操作系统下,通过API访问内存
C++:对内存封装,使用new创建对象分配内存,delete删除对象释放内存,若new了未delete,则造成内存泄漏
C#/Java:不直接操作内存,通过虚拟机来操作内存;若申请内存未释放,虚拟机会帮助释放内存
寄存器、缓存、内存的关系
寄存器离CPU最近,接下来是缓存,最后是内存
CPU只与寄存器中进行存取,寄存器从内存读取数据,但由于寄存器和内存读取速度相差太大,所以产生了缓存
缓存:一级缓存和二级缓存Cache
内存
ROM:PROM,EPROM,EEPROM
SRAM
SRAM:数据存入后,掉电才数据才消失
DRAM:必须在一定时间内刷新才能保持存储的数据,比SRAM慢,比ROM快,比SRAM
寄存器(Register)是 CPU 中用于存储数据的单元,而寄存器是位于 CPU 内部的单元。
位,字节,半字,字的概念和内存位宽
CPU32位系统一般指数据线位32位,数据线越多一次传输处理的数据越多,性能越好
若要向内存写入一个数据,向控制总线传输写指令,地址总线上面传输内存地址,数据总线传输要写入内存的数据。
内存单位:GB、MB、KB、B、bit
CPU和内存之间的数据传送单位通常是一个字长,32位的系统一个字为4byte
stm32是32bit处理器,所以它的字是32bit的(一次处理4字节长度的数据)。半字自然就是16bit(2字节);
内存编址以字节为单位,一个内存单元就是一个字节,无论多少位内存都以字节位单位进行内存编址
数据类型占用字节大小
占用的大小由编译器决定
数据类型+*是指针类型,是地址,地址线为32位,则所有的该类型占8个字节
int a = 5; 若为32位系统,占4个字节,若内存地址从0x30000000,代表一个字节长度,分配了4个连续的地址
数据总线,地址总线,存储容量的关系
地址总线AB
一个cpu的N根地址总线,则可以说这个CPU的地址总线宽度为N。这样cpu最多可以寻址2的N次方个内存单元。
数据总线DB
8根数据总线传送一个8位二进制,数据线数量相当于每单元的位数
存储容量
存储容量=单元数*每单元的位数,一般每单元位数都是8
例子:若256KB的SRAM具有8条数据线,则他具有多少条地址线,存储容量多少
256KB = 2^18B 地址线为18条,8位则数据线8条,存储容量256KB*8
管理内存---数组、结构体、栈、堆
数组
数组定义就是在内存开辟一块连续的内存空间,数组明就是开辟的内存空间的首地址
数组所有元素类型相同,数组大小在定义时给出,数组空间是连续的
结构体
解决数组中所有元素类型必须相同的问题
结构体变量名代表的是整个结构体变量,结构体定义后,编译器会为所有成员分配空间
结构体内嵌指针实现面向对象
栈
保存局部变量(非静态局部变量)
只有一个口,先进后出
局部变量自动完成入栈,自动分配内存,出栈
函数退出的时候局部变量就会被释放,所以不能返回局部变量地址
栈保存在函数调用所需的所有维护信息
局部变量值未初始化时,值是随机的,因为栈内存是反复使用的
栈是有大小的,栈的大小是可以设置的,但定义局部变量时不能太大,避免栈的一处
堆
容量不限,动态分配;申请和释放都需要手工进行
堆内存申请函数:malloc, calloc, realloc
堆内存申请需要给定大小,申请完成则空间大小不变
动态申请的数据存储在堆中
静态存储区
静态局部变量和全局变量存储在静态存储区
静态存储区的大小在编译时就确定了,随程序运行而分配空间,程序运行结束才释放内存空间
2、C语言位操作
常用操作符
按位与&,逻辑与 &&
位或 |,逻辑或 ||
位取反 ~ ,逻辑非!
位异或 ^
左移位
将一个数转为二进制,左移若干位,左移出的丢弃,右边补零
x >> n = x * 2^n;
右移位
将各二进制位全部右移若干位,左边二进制位补0或补1(若操作数是无符号数或有符号正数就补0,若为有符号负数就补1),右边的二进制位丢弃
对寄存器位操作
清零
&= 十六进制数,要清零的位设置为0,其他位设置为1
REG1 &= 0XFFFF00FF //将bit8~bit15清零,其他位不变
置一
|= 十六进制数,要置位的数设置为1,其他位设置为0
REG1 |= 0X0000FF00 //将bit8~bit15置1,其他位不变
位取反
^= 十六进制数,要取反的位设置为1,其他位设置为0
REG1 ^= 0x0000FF00 //将bit8~bit15置取反,其他位不变
若REG1 = 0xAAAAAAAA ,将bit8~bit15取反后,得到REG1 = 0xAAAA55AA
移位构建特定二进制数
移位来构造二进制
设置bit3~bit7和bit23~bit25位为1
结合位取反获取特定位位0的二进制数
宏定义完成位运算
宏定义来置位
定义一个32位二进制数x的第n位置1(右边算起,bit0算第一位)
宏定义清除某位
定义一个32位二进制数x的第n位清零(右边算起,bit0算第一位)
作者: light, 来源:面包板社区
链接: https://mbb.eet-china.com/blog/uid-me-4056283.html
版权声明:本文为博主原创,未经本人允许,禁止转载!
开发工匠 2023-10-12 08:49