tag 标签: C语言--内存和位操作

相关博文
  • 热度 4
    2023-10-9 13:46
    1837 次阅读|
    1 个评论
    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语言位操作 常用操作符 按位与&,逻辑与 && 位或 |,逻辑或 || 位取反 ~ ,逻辑非! 位异或 ^ 左移位 将一个数转为二进制,左移若干位,左移出的丢弃,右边补零 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算第一位)