- 博客(52)
- 收藏
- 关注
原创 【Linux】文件系统(一)
系统直接在 Group 1 的 Inode Table 中,往后跳过 4151 个 inode 结构体(每个 128 字节),找到第 4152 个。在 4KB 的数据块里,一个 128 字节的 inode 可以塞下 32 个。如果你格式化了一个 300GB 的分区,Super Block 里就记着:“本分区总共有 7864 万个数据块,总共有 196 万个 inode,目前全都是空的。如果有进程想创建一个文件,内核会先看一眼 Super Block,确认“嗯,还有空闲的 inode 和块”,才允许创建。
2026-10-20 12:00:52
53
原创 【stm32】I2C(三)——认识EEPROM的AT24C02
每次写入操作(不管是写1字节还是写1页)完成后,芯片内部需要时间把数据真正烧录到存储介质中。AT24C02,如果它们地址一样,主设备发数据时,两颗芯片都会应答,总线就短路了。:读写一个字节后,芯片内部地址指针会自动递增(+1),可以连续操作后续地址。:这是 24 系列 EEPROM 的固定标识,出厂就写死了,改不了。它内部按“页(Page)”管理,每页 8 字节,共 32 页。:如果从一页的中间开始写,并且写的数据超过该页的剩余空间,:可以指定任意地址,读取或写入单个字节。,覆盖本页之前的数据(
2026-10-18 20:12:53
179
原创 【Linux】一切皆文件和缓冲区
一切皆文件”的本质是:内核把一切硬件设备、网络资源都封装成了和。用户只需用一个整数fd,配合统一的方法(),就能操控整个系统。
2026-10-18 15:25:43
157
原创 【Linux】进程程序替换
exec函数族有 6 个库函数(execlexeclpexecleexecvexecvpexecvpe)和 1 个系统调用(execvel=list、v=vector、p=path、e=env。6 个库函数最终都调用execveexecve是唯一真正的系统调用。
2026-10-10 08:56:26
145
原创 【stm32】I2C(二)——Master和Slave之间的协议
如果Master发ACK:→ Slave认为Master还要继续读→ Slave继续发下一个数据→ 同时Master想发停止条件→ 两个设备同时控制SDA → 冲突如果Master发NACK:→ Slave知道Master读完了→ Slave释放SDA→ Master发停止条件→ 不冲突I2C 收发不对称:Master 写时没问题,Master 读时 SDA 归 Slave,Master 想发停止会和 Slave 抢 SDA。
2026-10-08 13:43:27
157
原创 【stm32】I2C(一)——初步理解和基本原理
如果想让I2C输出1或者高电平,只需要让N-MOS管断开,SDA就会上拉到VDD,输出高电平。如果想让I2C输出1或者高电平,只需要让N-MOS管闭合,SDA就会下接入VSS,输出低电平。在I2C复用GPIO的时候,使用开漏模式的时候,N-MOS管默认处于断开状态,它是一种串行、同步、半双工、两线制的通信总线,一根总线上可以挂多个设备。但是开漏模式下面,外部有电阻,防止可以外部的VDD和内部的GED短路。在数据手册的开头MCU的大体外设情况,就有I2C的介绍——两个I2C。(这个高电平在外面的,
2026-10-06 15:20:38
271
原创 【stm32】串口——在MCU内部的工作过程
官方并没有披露,推测是在控制地址总线的时候他的读写方向不一致,就把读写两个不同的方向看成两个不同的寄存器了。在参考手册内部有USART内部的图,但是过于复杂,先看简化的图,搞懂基本原理。这个数据寄存器有两个,一个是TDR一个是RDR那他们为什么指向同一块物理地址?要等TXE决定了能不能把数据是否为空,TC决定了数据是否发完。CPU是怎么控制USART的?——控制USART内部的寄存器。万一发送移位寄存器在发送的时候,又在TDR写入数据了怎么办?他也有一个寄存器进行辅助。
2026-10-04 20:17:04
262
原创 【Linux】进程的终止、等待
写代码的时候编译后一般会有三种结果示例写代码的时候通常会在main函数的最后面写一个return 0,这个表示的是这个返回值给谁的?——打印最近一个进程的进程退出码echo $?
2026-10-04 16:42:39
184
原创 【Linux】进程地址空间初步理解
当子进程的g_val被修改的时候,操作系统会第一时间知道,然后会在物理内存处增加一个内存空间存放子进程修改的值,把修改后g_val的值放到新的物理内存空间,但是他们的虚拟地址都是一样的——因此平常写代码&,访问的是虚拟地址。因为str指向的内容是放在了字符常量区的,当运行的时候,字符常量区的虚拟地址映射到物理内存的时候,由于str不能被修改,会发送权限拦截。进程挂起的时候,OS会查找页表对应的地址,把页表清空,再把代码和数据放到磁盘。在用户方面用的是0-3GB的内存,剩下的都是内核的。
2026-10-01 20:34:43
208
原创 【Linux】环境变量
命令行参数表(argv)和环境变量表(env)是程序启动时由main函数同时接收的两组信息,二者分工明确、配合紧密:argv来自用户在命令行输入的参数,告诉程序“要做什么”;env来自 shell 继承的系统环境变量,告诉程序“在哪里找资源、用什么配置”。程序运行时,先从argv解析出用户意图,再从env读取运行环境,两者结合才能正确完成任务——缺了argv,程序不知道用户想干什么;缺了env,程序找不到依赖的库和配置,也无法正常运行。以。
2026-09-28 15:30:23
193
原创 【Linux】进程优先级、切换和调度
问题答案O(1) 调度算法是什么?Linux 2.6 的调度算法,时间复杂度 O(1)核心数据结构?active 和 expired 是什么?活动队列(时间片未用完)+ 过期队列(时间片用完)怎么找下一个进程?从 bitmap 找最高优先级非空队列,取队头为什么是 O(1)?bitmap 查找和链表操作都是常数时间active 空了怎么办?交换 active 和 expired 指针为什么被淘汰?交互性差,被 CFS 取代核心理解。
2026-09-26 18:34:04
224
原创 【Linux】进程状态
因为会有内存不够用的情况,当内存的进程过多,不够用了,操作系统就会先检查阻塞状态的进程看看会不会先执行,先不执行的会把相应的代码和数据。释放掉的PCB,操作系统会可能会提前识别他是否可能会重复利用,那么OS就会复用废弃的PCB,减少释放内存的操作,这样就有了。阻塞状态的进程因为内存不够的原因OS把他放到磁盘的swap交换区,这个时候这个进程的状态就是阻塞挂起。就绪状态的进程因为内存不够的原因OS把他放到磁盘的swap交换区,这个时候这个进程的状态就是阻塞挂起。,如果内存够了就把他唤回到内存里面。
2026-09-25 21:42:36
221
原创 【Linux】进程的初步理解
但是从不同角度如果一段代码由父子进程共享,其中一方去修改的话,那么OS会在底层拷贝一份,让目标进程修改这个拷贝。在侠义上理解:操作系统包括内核(进程管理,内存管理,文件件管理,驱动管理)和其他程序(例如函数库,shell程序等等)。服务器 → 网络 → 你的网卡 → 内存 → CPU → 内存 → 显示器。当第二行代码执行完,会有变成两个进程,一个父进程一个子进程,都会执行下面的代码。关于fopen的使用可以用觉得路径+文件,也可以直接+文件去打开对应的文件。这样的管理就是进程的描述了。
2026-09-22 12:55:22
148
原创 【stm32】带你看懂RCC和时钟树在MCU内部的运行逻辑
在GPIO篇说过,ARM-CPU可以从flash中读取代码执行,但是他并不是自主的,而是通过叫做的硬件机制去执行的。时钟类似一个节拍器,以固定的频率给外设输送对应的电信号,催促外设进行工作。假设:让所有的设备接收到高电平才工作。可以看到,时钟源会产生高低电平的信号,驱使相应外设的运行。在现实生活中,工程师不可能都用到单片机的所有外设,如果给每个外设都给自动的给时钟信号,就会造成耗费电力,人力,很容易遭到市场的淘汰,因此只需要用到哪个外设就给对应的外设加时钟信号就可以了,这样了。
2026-09-21 18:36:55
130
原创 【stm32】GPIO(下篇)——统一编址、源码理解和输入模式
我们来看一下MCU内部的情况可以看到MCU和外设之间都有线去相互连接的,他们的彼此之间都是相互联系的,但是根据速度的需求,他们拉线的需求就不一样了。
2026-09-13 23:43:51
174
1
原创 【Linux】开发工具
原理编译时,把库函数的机器码直接复制一份,合并到你的可执行文件中。原理运行时,库函数的机器码不复制到可执行文件中,而是保留一个“引用”,程序加载时由系统动态加载到内存,多个程序共享同一份库代码。特点说明库文件后缀.so(shared object,共享库)生成时机运行阶段(程序加载时)可执行文件依赖外部库,缺库无法运行体积小(不包含库代码)内存占用小(多个程序共享同一份库)更新库更新后,程序无需重新编译对比维度静态链接动态链接库文件后缀.a(静态库).so(动态库/共享库)复制时机编译时。
2026-09-12 12:17:02
205
原创 【C++】红黑树——用颜色与旋转对抗退化的 O(N)
有些书把 NULL 结点(空指针)也当成黑色叶子结点(NIL),这样规则④的“路径”就更好数了。理解时知道有这个约定即可,代码实现中通常忽略 NIL。所有先把之前的AVL树的左右旋转的代码拿出来(不做解释了)旋转和AVL树是完全一样的,只是颜色的变化问题方面不同。红黑树不要求“严格平衡”,而是“近似平衡”,因此。,因为如果父亲是黑色,插入红色后直接结束插入了。(grandfather,爷爷)、(parent,父亲)、,插入删除效率更高。(cur,新结点)、(uncle,叔叔)
2026-09-01 15:31:51
370
原创 【C++】AVL树——维持高度平衡的旋转策略
h >= 1时,新增结点插入在e子树,e子树高度从h-1并为h并不断更新8->5->10平衡因子,引发旋转,其中8的平衡因子为-1,旋转后8和5平衡因子为0,10平衡因子为1。h == 0时,a/b/c都是空树,b⾃⼰就是⼀个新增结点,不断更新5->10平衡因子,引发旋转,其中8的平衡因⼦为0,旋转后8和10和5平衡因⼦均为0。,若插入后8的平衡因子是1,插入在f处(8的右边),插入后8的平衡因子是-1,插入在e处(8的左边),插入后8的平衡因子是0,则e,f是空的。parent子树旋转平衡。
2026-08-28 13:03:47
170
原创 【C++】从小区车库到英文词典:一篇彻底搞透二叉搜索树
Key/Value的场景和单独Key的区别并没有特别大,毕竟Value是Key的映射,稍微有点不同的就是Find函数要有返回值,构造的时候要多写Value,走到空没有找到就是不存在,如果这个树不支持插入相等的值,找到x就返回,因为x是唯一的,如果支持插入相等的值,那么他要找往深处的。2、不是空树,看插入的key是否插入到左子树还是右子树,根据搜索二叉树的特点,比根大的都是在右边的,比跟小的在左边,以此类推。从根开始比较查找x,根据特点,要找的值比根大,往右边找,要找的值比根小,往左边找。
2026-08-26 19:07:44
200
原创 【C++】多态——为什么父类指针能调用子类的函数?
概念说明位置__vfptr虚函数表指针,对象内部隐藏指针对象内存中(栈/堆)vftable虚函数表,存放虚函数地址的数组代码段/常量区虚函数带virtual的成员函数代码段动态绑定运行时到虚表查地址调用多态调用时静态绑定编译时确定地址直接调用非虚函数调用时。
2026-08-23 12:26:06
328
原创 【C++】继承——基类和派生类的配合
类+类名:: 继承方式+被继承(父类)类名例如class Student : public Person//类+类名:: 继承方式+被继承(父类)类名继承基类成员访问方式的变化类成员/继承方式public继承protected继承private继承基类的public成员派生类的public成员派生类的protected成员派生类的private成员基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员基类的private成员。
2026-08-21 22:02:15
215
原创 【C++】库函数学得很昏?可能是模板还没有理解好
在学习C语言的时候学习过交换的函数,这里用到C++的引用交换,但是可以看到如果对每一种类型都写一个交换的函数是特别的冗余,他们仅仅是类型不同,代码复用率低,每当有新的类型出现的时候就要写一个新的函数,为了解决这个问题就有了泛型编程。函数模板是代表了一类函数家族,家族的逻辑是一样的,但是他们的类型不一样,在函数传参的时候,函数模板会根据实参的类型产生特定的函数。通过上面的模板函数,就可以调用不同类型的参数的函数,不需要单独实现特定类型的函数。这个是定义了一个静态数组的类,如果不传参,默认的空间是10。
2026-08-20 14:34:57
186
原创 【C++】当迭代器不再是裸指针——从list的模拟实现带你看
说明一下这三个类是什么。list_node:是结点类,它包含了三个部分_data(存储数据)、_prev(指向前一个节点)、_next(指向后一个节点)。还有一个构造函数,初始化结点的时候会调用构造函数。list_iterator:迭代器类,他是指向结点指针的包装器,他的目的是为了遍历整个链表,内部只有一结点_node,他是结点的指针。list:链表容器类,,内部是维护一个带头结点的双向循环链表,额外维护_size结点的个数。迭代器类容器是为了方便用户去找对应的结点,所以都设为公有。
2026-08-18 10:53:19
197
原创 【C++】手写vector vs std::vector:从功能正确到性能达标
由于pos是迭代器类型的,他的返回值是_start,_finish的成员变量,由于在调用insert()的时候调用了reserve()开辟新空间,这个时候pos指向原理的空间不存在了,就造成了所有迭代器都失效的问题,所以这里同理这里先记录了原先容器的大小,通过容器的大小记录旧空间pos指向的位置,reserve完了之后,重新计算他的pos,让pos指向新的空间。写法2更为简便,而且他的时间复杂度是O(1),是传值传参,v调用拷贝构造的时候,v是v3的拷贝,如果拷贝抛异常,v1保持不变。
2026-08-14 23:00:04
221
原创 C++的内存管理
int main()// 1. 单个对象:使用 new 申请并构造// 调用 A(int) 构造函数// 调用 A(int, int) 构造函数// 2. 对象数组:使用已有对象拷贝构造// 调用拷贝构造// 3. 对象数组:使用临时对象// 4. 对象数组:使用聚合初始化(C++11 列表初始化)// 释放内存delete p1;delete p2;return 0;
2026-08-06 12:25:56
213
原创 一篇文章带你了解——栈和队列
栈:栈(stack)是限定仅在⼀端进⾏插⼊或删除操作的线性表。栈顶(top):能插入和删除的一端栈顶(bottom):不能插入和删除的一端出栈:删除数据(在栈顶)入栈:放入数据(在栈顶)——也叫压栈/入栈/进栈空栈:没用任何元素栈也被称为后进先出的顺序表(Last In First Out),简称LIFO结构。
2026-07-21 22:24:35
216
原创 一篇文章带你走进C++——入门基础
C++是由Bjarne Stroustrup在1979年于贝尔实验室开始开发的,最初在C语言基础上添加了面向对象编程特性,1983年正式命名为C++。它是一种通用编程语言,支持面向对象、泛型和函数式等多种编程范式。
2026-07-16 11:44:57
218
原创 数据结构——单链表
链表(Linked List)是一种线性表,由一系列节点(Node)组成,每个节点包含数据域和指针域,节点之间通过指针链接在一起。
2026-06-19 16:32:20
199
原创 数据结构入门——顺序表
/ 类型重定义,方便以后改成其他类型// 指向动态数组的指针int size;// 当前已有元素个数// 当前总容量(最多能装多少个)} SqList;这里我们不再像C语言那样int arr[],那样定义,把他放到一个结构体里面,他们是一个整体,定义了数组的同时,记录当前的元素个数和容量,方便对后续的增删查改提供实现的条件。
2026-06-10 16:53:22
204
原创 C语言指针,有些可能不是很清楚?
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。危害:1. 段错误(Segfault) — 访问非法地址导致程序崩溃2. 内存数据静默损坏 — 写入未知内存,破坏其他变量的值,导致难以调试的诡异 bug3. 安全漏洞 — 可能被利用执行任意代码(use-after-free 攻击)4. 二次释放(double free) — 对野指针再次 free 会破坏堆管理结构最麻烦的是第 2 点:程序不一定立即崩溃,而是在完全无关的地方出错,极难定位。
2026-05-30 13:29:26
242
原创 C语言操作符
操作符有哪些1、算术操作符:+、-、*、/、%2、移位操作符:<< 、>>3、位操作符:&、|、^4、赋值操作符:=、 += 、-= 、 *= 、 /= 、 %= 、 >= 、 &= 、 |= 、 ^=5、单目操作符:!、 ++ 、-- 、 & 、 * 、 + 、 、 ~ 、 sizeof ( 类型 )6、关系操作符:==、!7、逻辑操作符:&&、||、8、条件操作符:?9、逗号表达式:,10、下标引用:[]11、函数调用:()12、结构体成员访问:. ->
2026-05-17 16:55:56
416
原创 C语言数组和函数
形式参数re t_type 是函数返回类型• fu n_name 是函数名• 括号中放的是形式参数• {}括起来的是函数体如果函数定义放在调用之后,编译器从上往下扫描时会不认识该函数,需要提前声明。错误示例(定义在后)// 编译警告:未定义return 0;int is_leap_year(int y) { // 定义在后面// ...正确做法:在调用前声明函数原型。// 函数声明(原型)printf("闰年\n");return 0;// 函数定义return 1;else。
2026-05-14 23:17:08
358
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅