导图社区 嵌入式C语言自我修养
工欲善其事,必先利其器、计算机体系结构与CPU工作原理、 ARM体系结构与汇编语言、数据存储与指针、GNU C 编译器扩展语法精简。
编辑于2022-01-04 18:51:54嵌入式C语言自我修养
第一章 工欲善其事,必先利其器
1.代码编辑工具:Vim
Vim是一款纯命令行操作、功能可扩展、高度可定制的文本编辑工具
安装Vim
Ubuntu-->安装vim-->敲击下面命令 # apt-get install vim $ sudo apt-get install vim #开头,表示当前命令是以root权限运行的 $开头,表示当前命令是以普通用户权限运行的 Fedora/macOS-->安装vim-->使用下面的命令安装Vim # yum install vim # brew install vim 安装好后 ,在shell命令行下输入:vim 如果安装成功,就会启动Vim并弹出一个Vim界面,显示Vim版本号 查看版本号,用下面命令 # vim -v
Vim常用命令
vim常用的工作模式
1.普通模式:打开文件时的默认模式,在其他模式下按下ESC键都可返回到该模式 2.插入模式:按i/o/a键进入该模式,进行文本编辑操作,不同之处在于插入字符的位置在光标之前还是之后 3.命令行模式:普通模式下输入冒号(:)后会进入该模式,在该模式下输入命令,如输入:set number 或:set nu 可以显示行号 4.可视化模式:在普通模式下按v键进入可视化模式。在该模式下移动光标可以选中一个文本,然后进行复制、粘贴、删除等文本操作 5.替换模式:在普通模式下通过光标选中一个字符,然后按r键,再输入一个字符,你会发现你输入的字符就替换掉了原来那个被选中的字符
vim的命令
1.单个字符的移动
k:在普通模式下,敲击k键,光标向上移动一个字符 j:光标向下移动一个字符 h:光标向左移动一个字符 l:光标向右移动一个字符
2.单词移动
w:光标移动到下一个单词的开头 b:光标移动到上一个单词的开头 e:光标移动到下一个单词的词尾 E:光标移动到下一个单词的词尾(忽略标点符号) ge:光标移动到上一个单词的词尾 2w:指定移动光标2次移动到下下个单词开头
3.行移动
$:将光标移动到当前行的行尾 0:将光标移动到当前行的行首 ^:将光标移动到当前行的第一个非空字符 2|:将光标移动到当前行的第二列 fx:将光标移动到当前行的第一个字符x上 3fx:将光标移动到当前行的第3个字符x上 %:符号间的移动,在()、[]、{}之间跳跃
4.屏幕移动
nG:光标跳转到指定的第n行 gg/G:光标跳转到文件的开头/末尾 L:光标移动到当前屏幕的末尾 M:光标移动到当前屏幕的中心 Ctrl+g:光标查看当前的位置状态 Ctrl+u/d:光标向前/后半屏滚动 Ctrl+f/b:光标向前/向后全屏滚动
5.文本的基本操作
i/a:在当前光标的前或后面插入字符 I/A:在当前光标所在行的行首或行尾插入字符 o:在当前光标所在行的下一行插入字符 x:删除当前光标所在处的字符 X:删除当前光标左边的字符 dw:删除一个单词 dd:删除当前光标所在处的一整行 2dd:删除当前光标所在处的一整行和下一行 yw:复制一个单词 yy:复制光标所在处的下一行 p:粘贴,注意粘贴到光标所在处的下一行 J:删除一个分行符,将当前行与下一行合并
6.文本的查找与替换
/string:在Vim的普通模式下输入/string即可正向往下查找字符串string ?string:反向查找字符串string :set hls:高亮显示光标处的单词,敲击n浏览下一个 s/old/new:将当前行的第一个字符串old替换为new s/old/new/g:将当前行的所有字符串old替换为new %s/old/new/g:将文本中所有字符串old替换为new %s/^old/new/g:将文本中所有以old开头的字符串替换为new
7.文本的保存与退出
u:撤销上一步的操作 q:若文件没有修改,则直接退出 q!:若文件已修改,则放弃修改,退出 wq:若文件已修改,则保存修改,退出 e!:若文件已修改,则放弃修改,恢复文件打开时的状态 w!sudo tee %:在Shell的普通用户模式下保存root读写权限的文件 %表示当前的文件名,tee命令用来把缓冲区的数据保存到当前文件,这个命令会提示你输入当前用户密码,输入密码后选择OK确认,然后这个命令就可以提高权限,将你的修改保存到文件中
Vim配置文件:vimrc
显示行号的方法
在命令模式下输入:set nu命令 可以将这个命令写入Vim的配置文件,当用户使用Vim打开文件时,就不用每次都输入行号的命令了。 我们可以通过vim--version命令来查看Vim配置文件路径
配置文件
分为系统级配置文件和用户级配置文件 用户级配置文件只对当前用户有效,一般位于$HOME/.vimrc和~/.vim/vimrc这两个路径下,而系统配置文件对所有用户有效,一般位于/etc/vim/vimrc路径下
在vimrc中添加其他配置
set number "color schme colorscheme molokai "Backspace deletes like most programs in insert mode set backspace=2 "Show the cursor position all the time set ruler "Display incomplete commands set showcmd "set fileencodings set fileencodings =ucs -bom ,utf-8,cp936,gb2312,gb18030,big 5 set background=dark set encoding =uft-8 set fenc=utf-8 set smartindent set autoindent set cul set linespce=2 set showmatch set lines=47 columns=90 " font and size " set guifont=Andale Mono:h14 " set guifont =Monaco:h11 set guifont =Menlo:h14 " Softtabs,4 space set tabstop =4 set shiftwidth=4 set shiftround set softtabstop=4 set expandtab set smarttab " Highlight currunt line au WinLeave * set nocursorline au WinEnter * set cursorline
Vim的按键映射
添加按键映射命令
inormap [ [ ] <Esc>i inormap ] [ ] <Esc>i inormap ( () <Esc>i inormap ) () <Esc>i inormap " "" <Esc>i inormap { {} <Esc>i inormap } {} <Esc>i
添加组合键映射
由于方向键的键程较远,右手需要在字符键和方向键之间来回切换,十分不便,为了提高输入效率,可以通过组合键映射,在插入模式下使用组合键Ctrl+h,Ctrl+j,Ctrl+k,Ctrl+l来移动光标 inoremap <C-L> <Esc>la inoremap <C-H> <Esc>ha inoremap <C-J> <Esc>ja inoremap <C-K> <Esc>ka 快捷光标移动命令 imap ,, <Esc>la imap . . <Esc>2la
Vim官方网站可以下载插件扩展功能
先在当前用户下创建一个~/.vim/plugin目录,然后将xx.vim格式的插件复制到这个目录,在$HOME/.vimrc配置文件里对这些插件进行配置,就可以直接使用了
2.程序编译工具:make
使用IDE编译C程序
使用gcc编译C源程序
使用apt-get命令安装工具
# apt -get install gcc # apt -get install gcc-arm-linux-gnueabi 查看编译器版本 # gcc -v # arm-linux-gnueabi-gcc -v
gcc命令编译main.c源程序文件
# gcc -o hello main.c # ./hello hello world !
gcc的编译参数
-E:只对C源程序进行预处理,不编译 -S: 只编译到汇编文件,不再编译 -c: 只编译生成目标文件,不进行链接 -o:指定输出的可执行文件名 -g:生成带有调试信息的debug文件 -O2:代码编译优化等级,一般选择为2 -W:在编译中开启警告(warning)信息 -I:大写的I,在编译时指定头文件的路径 -l:小写的l(like的首字母),指定程序使用的函数库 -L:大写的L(like的首字母),指定函数库的路径
使用make编译程序
有main.c和 sum.c 如果我们使用gcc来编译程序,可以使用下列命令 # gcc -o hello main.c sum.c 如果我们为你想使用make工具来编译,首先要写一个makefile .PHONY:all clean all:hello hello:main.o sum.o gcc -o hello main.o sum.o main.o:main.c gcc -c main.c sum.o:sum.c gcc -c sum.c clean: rm -f main.o sum.o hello
Makefile规则组成
目标: 目标依赖 命令
3.代码管理工具:Git
什么是版本控制系统
Git的安装和配置
安装
# apt-get install git
配置
# git config --global user.email 325463632@qq.com # git config --global user.name “litao.wang” --global:配置~/.gitconfig 文件,对当前用户下的所有仓库有效 --system:配置/etc/gitconfig文件,对当前系统下所有用户有效 无参数:配置.git/config文件,只对当前仓库有效
Git常用命令
git init:创建一个本地版本的仓库 git add main.c:将main.c文件的修改变化保存到仓库的暂存区 git commit:将保存到暂存区的修改提交到本地仓库 git log:查看提交历史 git show commit_id:根据提交的ID查看某一个提交的详细的信息
操作演示1
新建一个目录tmp,在tmp目录下新建一个C源文件main.c # mkdir ~/tmp # cd ~/tmp # touch main.c 然后在tmp目录下新建一个Git仓库,并将main.c提交到仓库中 # git init 创建一个仓库 # git status 查看工作区状态 # git add main.c 将工作区修改的main.c添加到暂存区 # git status 查看工作区状态 # git commit -m "init repo and add main.c"将暂存区的修改提交到仓库 git log查看提交信息 # git log 如果提交后你又修改了main.c文件,使用下面命令 # git add main.c # git commit -m "modify main.c again:add add function"
操作演示2
然后使用git log 或者 git show命令来查看我们新的提交信息和修改变化,后面的数字是每一次提交的commit ID # git log # git show 545ef767734efdc434dfe34333f 如果想让提交不影响整个项目,则可以创建一个自己的分支my_branch分支上,切换到my_branch分支上,然后在这个分支上修改代码就可以了 # git branch my_branch //创建一个新分支my_branch # git checkout my_branch //切换到新分支my_branch # git commit -m "on my_branch:modify main.c " //将修改提交到my_branch # git log # git checkout master //切换到 master 分支,在该分支上看不到新的提交信息 # git log # git merge my_branch // 将my_branch分支上的修改合并到master分支 # git log
第二章 计算机体系结构与CPU工作原理
1.一颗芯片是怎样诞生的
从沙子到单晶硅
沙子-->化学反应-->还原成硅-->提纯-->多晶硅-->切片-->晶圆(每一个小格子叫晶粒)-->对晶圆上的这些芯片电路切割、封装、引出引脚-->芯片 多晶硅掺杂-->放入晶种-->硅棒缓慢往上拉并旋转-->单晶硅开始生长-->最后成品:硅棒
PN结的工作原理
从PN结到芯片电路
半导体工艺流程
电路图-->投影曝光-->光刻掩膜版-->光刻-->光刻胶-->离子注入-->芯片电路
芯片的封装
2.一颗CPU是怎么设计出来的
计算机理论基石:图灵机
无限长的纸带:相当于程序代码 一个读写头Head:相当于程序计数器PC 一套控制规则Table:相当于CPU有限的指令集 一个状态寄存器:相当于程序或计算机状态输出
CPU内部结构及工作原理
结构
算术逻辑运算单元(ALU)、控制单元、寄存器 指令集:CPU支持的有限个基本指令集合
高级语言的编译流程
C程序 ---->C编译器 ----->汇编指令--->汇编器--->二进制指令 C++程序---->C++编译器
CPU设计流程
1.设计芯片规格
2.HDL代码实现
3.逻辑综合
4.仿真验证
5.后端设计
3.计算机体系结构
冯•诺依曼架构
哈弗架构
混合架构
4.CPU性能提升:Cache机制
Cache的工作原理
一级Cache和二级Cache
为什么有些处理器没有Cache
5.CPU性能提升:流水线
流水线工作原理
超流水线技术
流水线冒险
分支预测
乱序执行
SIMD和NEON
单发射和多发射
6.多核CPU
单核处理器的瓶颈
片上多核互连技术
big.LITTLE结构
超线程技术
CPU核数越多越好吗
7.后摩尔时代:异构计算的崛起
什么是异构计算
GPU
DSP
FPGA
TPU
NPU
后摩尔时代的XPU们
8.总线与地址
地址的本质
总线的概念
总线编址方式
9.指令集与微架构
什么是指令集
什么是微架构
指令助记符:汇编语言
第三章 ARM体系结构与汇编语言
1.ARM体系结构
2.ARM汇编指令
存储访问指令
数据传送指令
算术逻辑运算指令
操作数:operand2详解
比较指令
条件执行指令
跳转指令
3.ARM寻址方式
寄存器寻址
立即数寻址
寄存器偏移寻址
寄存器间接寻址
基址寻址
多寄存器寻址
相对寻址
4.ARM伪指令
LDR伪指令
ADR伪指令
5.ARM汇编程序设计
ARM汇编程序格式
符号与标号
伪操作
6.C语言和汇编语言的混合编程
ATPCS规则
在C语言中内嵌汇编代码
在汇编程序中调用C程序
7.GUN ARM汇编语言
重新认识编译器
GUN ARM 编译器的伪操作
GUN ARM 汇编语言中的标号
.section伪操作
基本数据格式
数据定义
汇编代码分析实战
第四章 程序的编译、链接、安装和运行
1.从源程序到二进制文件
2.预处理过程
3.程序的编译
从C文件到汇编语言
汇编过程
符号表与重定义表
4.链接过程
分段组装
符号决议
重定位
5.程序的安装
程序安装的本质
在Linux下制作软件安装包
使用apt-get在线安装软件
在Windows下制作软件安装包
6.程序的运行
操作系统环境下的程序运行
裸机环境下的程序运行
程序入口main()函数分析
BSS段的小秘密
7.链接的静态库
8.动态链接
与地址无关的代码
全局偏移表
延迟绑定
共享库
9.插件的工作原理
10.Linux内核模块运行机制
11.Linux内核编译和启动分析
12.U-boot重定位分析
13.常用的binutils工具集
第五章 内存堆栈管理
1.程序运行的马甲:进程
2.Linux环境下的内存管理
3.栈的管理
栈的初始化
函数调用
参数传递
形参与实参
栈与作用域
栈溢出攻击原理
4.堆内存管理
裸机环境下的对内存管理
uC/OS的堆内存管理
Linux 堆内战管理
堆内存测试程序
实现自己的堆管理器
5.mmap映射区域探秘
将文件映射到内存
mmap映射实现机制分析
把设备映射到内存
多进程共享动态库
6.内存泄漏与防范
一个内存泄露的例子
预防内存泄漏
内存泄漏检测:MTrace
广义上的内存泄漏
7.常见的内存错误及检测
总有一个Bug,让你泪流满面
使用core dump调试段错误
什么是内存踩踏
内存踩踏监测:mprotect
内存检测神器:Valgrind
第六章 GNU C 编译器扩展语法精简
1.C语言标准和编译器
什么是C语言标准
C语言标准的内容
C语言标准的发展过程
编译器对C语言标准的支持
编译器对C语言标准的扩展
2.指定初始化
指定初始化数组元素
指定初始化结构体成员
Linux内核驱动注册
指定初始化的好处
3.宏构造利器:语句表达式
表达式、语句和代码块
语句表达式
在宏定义中使用语句表达式
内核中的语句表达式
4.typeof与container_of宏
typeof关键字
typeof使用示例
Linux内核中的container_of宏
container_of宏实现分析
5.零长度数组
什么是零长度数组
零长度数组使用示例
内存中的零长度数组
思考:指针与零长度数组
6.属性声明:section
GNU C编译器扩展关键字:_attribute_
属性声明:section
U-boot镜像自复制分析
7.属性声明:aligned
地址对齐:aligned
结构体的对齐
思考:编译器一定会按照aligned指定的方式对齐吗
属性声明:packed
内核中的aligned、packed声明
8.属性声明:format
变参函数的格式检查
变参函数的设计与实现
实现自己的日志打印函数
9.属性声明:weak
强符号和弱符号
函数的强符号和弱符号
弱符号的用途
属性声明:alias
10.内联函数
属性声明:noinline
什么是内联函数
内联函数与宏
编译器对内联函数的处理
思考:内联函数为什么定义在头文件中
11.内建函数
什么是内建函数
常用的内建函数
C标准库的内建函数
内建函数:__builtin_constant_p(n)
内建函数:__builtin_expect(exp,c)
Linux内核中的likely和unlikely
12.可变参数宏
什么是可变参数宏
继续改进我们的宏
可变参数宏的另一种写法
内核中的可变参数宏
第七章 数据存储与指针
1.数据类型与存储
大端模式和小端模式
有符号数和无符号数
数据溢出
数据类型转换
2.数据对齐
为什么要数据对齐
结构体对齐
联合体对齐
3.数据的可移植性
4.内核中的size_t类型
5.为什么很多人编程时喜欢用typedef
typedef的基本用法
使用typedef的优势
使用typedef需要注意的地方
6.枚举类型
使用枚举的三种方法
枚举的本质
Linux内核中的枚举类型
使用枚举需要注意的地方
7.常量和变量
变量的本质
常量存储
常量折叠
8.从变量到指针
指针的本质
一些复杂的指针声明
指针类型与运算
9.指针与数组的暧昧关系
下标运算符[]
数组名的本质
指针数组与数组指针
10.指针与结构体
11. 二级指针
修改指针变量的值
二维指针和指针数组
二级指针和二维数组
12.函数指针
13.重新认识void
第八章 C语言的面向对象编程思想
1.代码复用与分层思想
2.面向对象编程基础
什么是OOP
类的封装与实例化
继承与多态
虚函数与纯虚函数
3.Linux内核中的OPP思想:封装
类的C语言模拟实现
链表的抽象与封装
设备管理模型
总线设备模型
4.Linux内核中的OPP思想:继承
继承与私有指针
继承与抽象类
继承与接口
5.Linux内核中的OPP思想:多态
第九章 C语言的模块化编程思想
1.模块的编译和链接
2.系统模块划分
模块划分方法
面向对象编程的思想陷阱
规划合理的目录结构
3.一个模块的封装
4.头文件深度剖析
基本概念
隐式声明
变量的声明与定义
如何区分定义和声明
前向引用和前向声明
定义与声明的一致性
头文件路径Linux内核中的头文件
头文件中的内联函数
5.模块化设计原则
6.被误解的关键字:goto
7.模块间通信
全局变量
回调函数
异步通信
8.模块设计进阶
跨平台设计
框架
9.AIoT时代的模块化编程
第十章 C语言的多任务编辑思想和操作系统入门
1.多任务的裸机实现
多任务的模拟实现
改变任务的执行频率
改变任务的执行时间
2.操作系统的基本原理
调度器的工作原理
函数栈与进程栈
可重入函数
临界区与临界资源
3.中断
中断处理流程
进程栈与中断栈
中断函数的实现
4.系统调用
操作系统的API
操作系统的权限管理
CPU的特权模式
Linux系统调用接口
5.揭开文件系统的神秘面纱
什么是文件系统
文件系统的挂载
根文件系统
6.存储器接口与映射
存储器与接口
存储映射
嵌入式启动方式
7.内存与外部设备
内存与外存
外部设备
I/O端口与I/O内存
8.寄存器操作
位运算应用
操作寄存器
位域
9.内存管理单元MMU
地址转换
权限管理
10.进程、线程和协程
进程
线程
线程池
协程
小结