嵌入式软件工程师学习路线 朱有鹏老师语录:学习如走夜路,人多心里不慌。
1、嵌入式基础预科
2、ARM裸机全集
3、C语言高级专题
4、Uboot和系统移植
5、Linux应用编程和网络编程
6、Linux驱动开发实战
----------------------------------------------------
内存这个大话题
C语言:C语言中编译器帮我们管理直接内存地址。通过编译器提供的变量名等来访问内存。
大块内存通过API(malloc free)来申请释放内存。
JAVA/C#:不直接操作内存,通过虚拟机操作内存,管理,释放内存。虚拟机回收内存需要付出代价。
C语言就如同,在家吃饭,自己洗碗。
java/C#等高级语言如同,在外面吃饭,吃完就走了,但是要付出一定代价。
C语言中一个变量实际就对应内存的一个单元。
内存单元的大小单位
-----------------
位bit 1bit
字节byte 8bit
半字 一般16bit
字 一般32bit
------------------
CPU只认识内存地址,地址和空间是内存单元的两个方面.
内存编址是以字节为单位.
------------------------------------------------------------------------------------------
数据类型
C语言基本数据类型 char short int long float double
int 整型(整数类型,这个整就体现在它和CPU本身的数据位宽一样)
32bit的CPU == 整型就是32bit == int 32bit
数据类型是用来定义变量,而这些变量需要存储、运算在内存中。所以数据类型必须和内存相匹配才能获得最好的性能,否则可能不工作或者效率低下。
在32位系统中定义变量最好用int,因为这样效率高。原因就在于32位系统.本身配合内存等也是32bit,这样的硬件配置天生适合定义32bit的int类型变量,效率最好。也能定义8bit的char或16bit的short,实际访问效率不高.
在32bit环境下,定义bool类型变量,(实际只需要1个bit),都是用int来实现bool
编译器帮分配了int来存储bool,实际浪费了31bit的内存,但是效率高。
问题:实际编程时要以省内存为大还是要以运行效率为重?看具体情况
现在写程序重要是效率和用户体验关键。(内存变得便宜,不在乎)
内存对齐
定义int 4个字节
0 1 2 3 对齐访问
1 2 3 4 / 2 3 4 5 / 3 4 5 6 非对齐访问
内存的对齐访问不是逻辑问题,硬件的问题。32位的内存0 1 2 3 逻辑就有相关性,硬件上合适,效率高。
对齐访问很配合硬件,效率很高;
非对齐访问因为和硬件本身不搭配,效率不高
因为兼容性的问题,一般硬件也都提供非对齐访问,但是效率低
----------------------------------------------------------------------------
C语言对内存地址的封装(用变量名来访问内存、数据类型的含义、函数名的含义)
数组 连续的空间
首地址
首元素
首元素的首地址
int a;//编译器申请一个int类型的内存格子(长度4字节,地址确定,符号a与这个格子绑定)
a = 5;// 5 丢到 符号a绑定的格子里去
a += 4;//9
C语言中数据本类型的本质含义是:表示一个内存格子的长度和解析方法.
数据类型决定长度的含义:
我们一个内存地址,本来这个地址只代表1个字节的长度,给他一个类型,让他有了长度.这样这个代表内存地址的数字就能从这个数字开头的连续n个字节的内存格子。
数据类型决定解析方法的含义:有一个内存地址,给这个内存地址不同的类型来指定这个内存单元格子中二进制数的解析方法.
(int)0x30000000 4个字节连起来共同存储是一个int
(int *)0; //0数据的地址解析方式-int*类型(0存一个指针,指向int)
(float *)0;
(short)0;
(char)0;//0 地址存一个char变量
函数就是一段代码的封装,函数名的实质就是这一段代码的首地址。
函数名的本质就是一个内存地址.
用指针来间接访问内存
类型只是对后面数字或者符号(内存地址)所表征的内存的一种长度规定和解析方法
数组管理内存和变量,只是符号的解析方法不同
int a; //编译器分配4字节长度给a,并且把首地址和符号a绑定.
int b[10];//编译器分配40个字节长度给b,首元素的首地址和b绑定.
-------------------------------------------------------------------------------
内存管理之结构体
数据结构就是研究数据如何组织(在内存中排布)如何加工
数组下标访问,编译器帮计算内存地址
a[0] a[2] = a[0] + 2*4
数组-优点 :数组比较简单,访问用下标,随机访问
缺点 : 元素类型必须相同,大小必须定义时给出,一旦确定不能再改。
结构体发明解决数组的第一个缺陷:数组中所有元素类型必须相同
结构体内嵌指针实现面向对象。
C语言是面向过程的,但是C语言写出linux系统是面向对象的。
用C++ java等面向对象的语言来实现面向对象简单一些,因为语言本身帮我们做了很多事情;但是用C来实现面向对象很麻烦。
struct a
{
int age;
void (*func)(void);//函数指针,指向void func(void)这类的函数
};
使用这样的结构体就可以实现面向对象。这样包含了函数指针的结构体就类似于面向对象的class。结构体中的变量类似于class的成员变量。函数指针类似于class的成员方法。
-------------------------------------------------------------------------------------------
栈是一种数据结构,C语言使用栈保存局部变量,管理内存)
栈管理内存特点(小内存、自动化)
C语言中的局部变量用栈来实现的。
定义一个局部变量时,编译器会在栈中分配一段空间,栈指针的移动和内存分配时自动(栈自己完成)
函数退出,局部变量灭亡,出栈。
C语言中,定义局部变量,如果未初始化,值随机,栈内存反复使用(脏的,上次用完没清零)
显示初始化
int a = 15;//局部变量定义时,初始化
C语言编译器自动把这行转成
int a; //定义
a = 15;//赋值
栈的约束(预定栈大小不灵活,怕溢出)
栈是有大小的。栈内存大小不好设置。太小怕溢出,太大怕浪费内存。
C语言定义局部变量不能太多,太大,递归问题要递归收敛一点。
-------------------------------------------------------------------------------------------
堆 堆栈(栈)
heap 内存管理(随时申请、释放、大小块随意)
堆内存,向使用者(用户进程)提供API(malloc和free)
需要内存容量比较大,需要反复使用及释放(数据结构的实现-链表)
堆管理内存特点
1 容量不限
2 申请、释放 手工进行malloc free,未释放-内存丢失,内存泄漏
堆管理器中内存仍属于这个进程,但进程自己又一位这段内存不用了,再用的时候又会去申请的内存这叫吃内存
C/C++ 内存泄漏最严重的程序bug
Java / C# 内存管理,只需要使用,不需要释放
man 3 free man手册
void free(void *ptr);
堆内存申请
realloc、calloc、malloc
void *malloc(size_t size);
void *calloc(size_t nmemb,size_t size);// 多少 单位
void *realloc(void *ptr,size_t size);//改变原来申请空间的大小
数组定义大小无法更改
java中障眼法-更改数组大小
1、先重新创建一个新数组的大小
2、原数组的元素复制进新的数组
3、释放原数组
4、返回新数组给用户
堆内存申请给大小,一旦申请完成大小不变,如果要变通过realloc
申请10个int元素内存
malloc(40) malloc(10*sizeof(int));
calloc(10,4) calloc(10,sizeof(int));
------------------------------------------------------------------------------------------