高质量有效编程笔记

article/2024/4/20 15:16:55

来自李云的高质量有效编程电子书的摘抄,有些需要进一步实践

高质量有效编程笔记:
硬件部分
1、 微处理器、微控制器,从编程角度无区别。
2、 寄存器:通用寄存器GPR、浮点寄存器FPR
3、 通用寄存器GPR:执行指令、整数运算、逻辑运算
4、 程序计数器PC==指令指针IP
5、 栈指针寄存器SP、ESP。
6、 芯片手册比较权威,例如INTER X86
7、 硬件设计了CPU上电后PC、IP的初始值,硬件设计了地址与外设间的映射。
8、 第一条指令一般指向引导加载器程序。
9、 CPU、内存、外设。CPU与外设之间的通信:输入、输出。以太网、RS232、USB、闪存、采集、动作设备
10、 外设也通过地址区分,IO端口。IO中断。IO空间。
11、 X86:独立IO地址空间64KB、内存映射IO空间。
12、 ARM、PowerPC只有内存映射IO空间。
13、 IO端口实际是外设寄存器再CPU的IO地址。对IO端口读写实际是对外设寄存器读写。如何读写查芯片手册。
14、 指令、数据。以段的形式组织。
15、 中断,处理器初始化阶段设置中断服务程序ISR。中断控制器。从外设读取中断寄存器的值,处理完后设置外设寄存器,清除中断信号标识。
16、 中断触发方式:高低电平触发、上升沿触发、下降沿触发。
17、 硬中断、软中断。中断优先级。中断嵌套。中断寄存器。
18、 字节序:小尾win、大尾
19、 边界对齐:与CPU位数有关。函数边界一般是0x10。还涉及换页,页边界4096 0x1000(编译时的大小优先、速度优先?)
20、 Solaris对边界未对齐的不支持,例如LD指令
21、 程序断点(指令断点)、数据断点
22、 软件程序断点:在断点处,用asm int 3替换原指令,中断后,用原指令替换回来,继续执行,并通知debug。数量无限制。
23、 硬件程序断点:断点寄存器,数量有限,4个。
24、 数据断点:寄存器中存储要监视数据的地址,数据变更时中断。个数有限。
25、 内存管理单元MMU:虚拟内存、内存保护(读、写、可执行)。
26、 嵌入式系统一般无虚拟内存。只用于内存保护。
27、 当只读内存区被改写时,会产生异常中断。可查函数调用栈。
28、 页大小4KB、0x1000、4096。内存边界以页为单位。
29、 缓存:一级缓存、二级缓存、缓存命中、缓存锁定。
30、 操作闪存一般禁止缓存。
31、 硬件,信号完整性问题(电容效应),高频电路的信号完整性容易出问题。往往是布线不合理导致。信号干扰。
32、 需要参考开发板。频率适用即可,太快容易出问题。
工具部分
33、 Make开发环境、makefile:目标target、依赖关系dependency、命令command、规则rule,注释以#开头
34、 Makefile中命令必须以tab开头,不可用空格替代
35、 Makefile有默认目标(第一个目标),多个目标
36、 目标在:左边,先决条件在:右边。命令在后续行的tab后
37、 Make all test…是指定生成目标
38、 Make按照从左到右、从上到下构建依赖关系图
39、 :左右都可以有多个目标
40、 在windows中用cygwin环境测试makefile、gnu、gcc等
41、 Makefile需要判断文件时间,如果拷贝破坏了文件时间,需要make clean等
42、 假目标, .PHONY clean 防止存在clean文件,makefile无法识别clean的含义
43、 Makefile变量: CC=gcc RM=rm EXE=simple.exe OBJS=main.o foo.o (EXE):(EXE):(EXE):(OBJS) …
44、 makefile自动变量:@规则中的目标、@ 规则中的目标、@规则中的目标、^规则中的先决条件、<规则中的第一个先决条件…45、makefile中输出<规则中的第一个先决条件… 45、 makefile中输出<规则中的第一个先决条件45makefile中输出转义符,需要$$
46、 $@在bash有含义,所以需要再转义 $$@
47、 MAKE变量:当前处理makefile的命令名,一般为make
48、 MAKECMDGOALS变量:当前构建的目标名,默认目标时不显示目标
49、 递归扩展变量用=,简单扩展变量用:=(无递归,只有一次展开)
50、 条件赋值用?= 没定义就用右边的赋值,否则不赋值
51、 追加赋值 +=
52、 Make时设置变量值
53、 Makefile中的后缀替换
54、 Override防止变量被覆盖
55、 精简规则 %.o:%.c $(CC) –o $@ -c $^
56、 Makefile支持多种函数对文件名等数据进行处理
57、 Makefile调试:通过make –d –debug查看过程,通过echo显示变量
58、 GCC 是“ GNU Compiler Collection,支持C、C++、java、ObjectC…
59、 交叉编译( cross compiling )交叉编译器、交叉链接器、交叉编译环境等。目标机的处理器与开发主机的处理器不同。
60、 预处理( preprocessing、cpp、输出c)、编译( compilation、cc、输出s )、汇编( assembly、as、输出o )和链接( linking、ld、输出exe)
61、 gcc使用-E 选项获得 main.pre.c 文件,方便分析宏错误
62、 gcc使用-S –O2输出汇编程序,帮助写汇编、了解C语言细节
63、 gcc –v获得系统头文件路径
64、 gee 的-WI在项用于指定传递给链接器的选项,-Map=main.map 选项由 gcc 传递给链接器以指示链接器为战们生成名为 main.map 的映射文件。映射文件中除了包含 nm工具所获取的信息外,还包含各符号来源于哪一个库及库中的哪一个目标文件等更为详细的信息 。
65、 gcc –D定义宏
66、 gcc –M获得依赖关系、-MM成不包含系统头文件的依赖关系
67、 gcc –L指定在哪查找库文件,-l指定链接库,按调用顺序指定lib
68、 binutils 工具集:as 是汇编编译器,用于将汇编代码转换为目标文件 。addr2line 用 于得到程序指令地址所对应的函数,以及函数所在的源文件名和行号 。ar 用于创建和修改档案文件,以及从档案文件中抽取文件。静态库( .a 文件)就是一种档案文件,需要用它生成和管理 。Id 是链接器。nm 用于列出程序文件中的符号及符号在 内存中的(开始)地址 。符号包含 C 程序中的函数名和变量名。objcopy 可以用来从程序文件中拷贝出我们所指定的段。objdump 能显示程序文件的相关信息和对程序文件进行反汇编。ranlib 用于生成一个档案文件的内容索引 ,以加快对档案文件的查找速度。将该工具运用于静态库能提高库参与链接的效率。size 用于了解程序文件中各段的大小 。strings 用于查看’程序文件内 的可显示字符串 。strip 用于剥去程序文件的调试信息 ,以减小程序文件所占用 的存储空间。
69、 采用 GNU 工具集进行开发时 , 一个静态库其实就是将.o文件打包而生成的档案文件。静态库.a 动态库.so
70、 初始化的数据段.data段,未初始化的数据段.bss段、只读数据段.rdata段、代码段.text段
71、 段地址存在 VMA ( Virtual Memory Address,虚拟内存地址〉和 LMA (Load Memory Address ,加载内存地址〉之别。
72、 strings 查看程序文件中的可显示字符,例如密码。
73、 gdb支持core文件,支持调试正在运行的程序
74、 break b指定断点位置,也可以加if条件断点,可以指定线程号
75、 tbreak指定一次有效的断点、rbreak指定正则表达式断点
76、 info breakpoints查看断点、disable、enable控制断点是否有效、delete删除断点
77、 ignore命令可以让 gdb 忽略程序碰到某断点的次数
78、 hbreak 命令可以设置硬件程序断点 , 其命令格式与 break 是完全一样的。通过 show命令可以了解处理器所支持的硬件断点数
79、 数据断点的设置需要使用 watch 命令
80、 gdb 还提供了 catch 命令以使我们捕获调试期间的事件,事件包括信号、程序开始、程序终止和 C++中的异常( exception )等
81、 gdb run start continue next step
82、 list显示调试附近的代码、until到指定位置、finish一个函数、return强制返回
83、 nexti、stepi控制单步汇编执行
84、 set可以改变变量值、print显示变量值、x检查内存区域值
85、 info reg $ebp、 print $ebp查寄存器值
86、 backtrace查调用栈
87、 使用“ info locals”可以查看函数的所有局部变量的值,使用 info args可以查看函数参数的值,使用“ info frame”可以看到当前战帧的信息、Disassemble看汇编
编程语言部分
88、 汇编命令都是以" .” 开头的 , 用于指示as 如何处理我们所写的汇编代码。
89、 .globle命令使得跟在其后的符号在文件之外可见, 或者从 C 语言的角度来看,类似于定义全局函数 。
90、 .align 命令是告诉 as 后面代码的存放地址必须满足 4 字节边界对齐
91、 .text 和.data命令指示将其后的 内容放入指定段中,.lcomm 和 .comm指示将其后的内容放入程序的.bss 段中。
92、 用符号( symbol )定义变量、函数。符号后面加上一个:就成为 了标签( label ),类似函数
93、 不论是 AT&T 语法还是Intel 语法as 都支持,可以通过 .att_syntax和.intel_syntax 汇编命令来切换指令格式。
94、 AT&T用后缀字母“ b(byte)”、“w(word)"、“ l(long)”、“ q(quardruple)”分别表示单字节 、 双字节 、 四字节和八字节。Intel没有此后缀
95、 当使用 “ q”、“ r”和“ g”这些限制时 ,表示由编译器自动完成寄存器的分配 。 那如何在嵌入的汇编中引 用被编译器 自 动分配的寄存器呢?这得通过“%N ”这样的格式加以引用的,其中的 N 可以从 0 到 9,N 指示了寄存器在 “输出 寄存器”和“输入寄存器”列表中的索引 。
96、 代码段.text,数据段.data 、. bss 和.rdata、栈、堆
97、 初始化不为 0 的变量,编译然会将它放入.data 段中
98、 没有初始化的变量也像初始化为 0 的变量那样被放入.bss 段。.bss 段所在的内存区全部初始化为 0。局部变量并不一定初始化。
99、 由于.bss 段中的变量不需要初始化成特定值( 0 除外〉,所以不需要在程序文件中保存其内容,其好处是能减小程序文件的大小而节省存储空间 。
100、 除了 .text、.data 和 .bss 三个段外,在程序中还可能存在其他的段。不管各段的名称有多么不同,但都逃不出它们只能属于指令、数据和调试信息三个类别 。
101、 栈的作用:当中断发生时用于保存处理器寄存器的值。用做函数参数和局部变量的存储空间 。
102、 栈操作通过处理器的栈指针寄存器〈后面简称栈指针或 SP )来完成的 。压栈、退栈。压栈,SP变小,低地址是栈顶,高地址是栈底。从栈底往栈顶增长。栈底不可变。
103、 压栈操作的具体顺序是 , 先更新 SP 的值,然后将于寄存器的值放入 SP 所指向的栈空间中。退栈顺序相反,先将 SP 所指向栈空间中的值放入寄存器中,然后调整 S P .
104、 堆:闲置内存用于堆。
105、 ABI是“ Application Binary Interface的缩写 ,即应用程序二进制接口,它是编译器和我们编写汇编代码时需遵循的规范 。EABI 中的 E 是“ Embedded”,它的提出是为了适应嵌入式系统资源更为有限这一现象 。EABI 使得生成的程序更节约内存资源。
106、 在 ABI 规范中所定义的内容:软件安装、底层系统信息、目标文件格式、加载和链接、库接口、开发环境、可执行环境。
107、 ABI底层系统信息:类型定义、字节对齐方式、寄存器功能分配
108、 EAX函数返回值、EDX被除数、ECX计数。EBX、ESI、EDI局部变量。
109、 栈由栈帧组成,每个栈帧对应一个(未执行完的〉函数.
110、 "在实现函数时 , 其参数应当尽虽用指针而不是用结构体以便提高效率”这一原则对于 PowerPC 处理器上的程序并不成立 。 但无论如何 , 养成函数参数传指针而非结构体这一编程,习惯还是有益的。
111、 在 x86 处理器上 ,当被调用函数需要返回结果给调用函数时存在两种情形。 一种是返回的数据是标量(比如整型、指针等〉 , 在这种情形下,返回值将会放入 EAX 寄存器中。如果返回的是浮点数,则返回值是放在协处理器的寄存器栈上的 。
112、 函数需要返回结构体或联合体(非标量) 。 这种情形需要通过栈来完成。
113、 在编写程序时,应当将一个外部需要引用的变盘或者函数放在一个头文件中,然后让定义和引用它们的源文件同时包含官,这种包含就为各“信息孤岛”间边立起了联系。永远采用头文件作为定义和引用的桥梁。
114、 编写与外设打交道的程序时需要注意运用 volatile 关键字,否则可能出现程序在不采用编译优化选项时能正常运行,而使用编译优化选项就不正常。volatile易变的。
设计部分
115、 设计的简单、优雅、美感、时间控件冗余度、代码冗余度。从共性、规律入手。分而治之。
116、 缺陷能否通过设计避免?是不是现在的设计注定了会出现这么多的缺陷 , 是否可以通过改善设计来真正有效、彻底地解决问题?从测试的角度思考如何设计才更方便测试。
117、 鼓励风险尝试。预研新的方案。
118、 如何提高设计能力:追求完美、实践、模仿、思考并形成设计思想。设计模式、设计原则和设计思想。
119、 灵活性设计在不少情形下是一个优美的陷阱,要避免踏入这一陷阱。用直截了当 的方式解决问题。
120、 模块初始化与释放。
121、 收集统计信息。时间、内存、cpu等。
122、 命名准确。
123、 关注审美告警。
124、 设计通用机制来预防潜在的问题。
125、 防止第三方犯错。
126、 考虑易于差错。输出日志,代价较高。设置状态位,代价较低。
127、 分层:平台层、框架层、应用层。分级。
128、 模式化的模块管理方式:状态标识、回调函数。
129、 错误码格式:最高位MSB为1,15位模块码,16位错误标识。
130、 错误码的名称应当采用“ERROR_模块名-动作-错误描述”这种统一的格式。尽量不复用错误码。
131、 输出错误的代价。集中输出。达到一个平衡。
132、 系统库、平台(eg:日志库、跨平台封装定义)、框架(eg:状态机、TCP网络通信)。打造公司级别的平台、框架。应用只基于框架、平台,不涉及系统,方便移植。
133、 尽量将嵌入式设备代码放到开发主机中测试。提高效率。例如模拟硬件、模拟显示。
操作系统(需要具体实现)
134、 嵌入式系统中,通常将整个系统的软件分成两大部分,分别是引导加载器( boot loader)和应用程序。注意:操作系统被包含在应用程序中.
135、 引导加载器的第一个功能是引导系统运行。引导的结果是完成最小系统的初始化 。 最小系统是指为了实现引导加载器功能所需的最基本硬件和软件。对处理器进行初始化。 包括:处理糕的工作时钟频率设置:各片选空间的时序和地址空间的配置:内存控制器的初始化:中断控制器的初始化:枝寄存器的初始化:等等。对外设和相关的软件模块进行初始化(显示器、网络等)。加载并执行应用程序。升级应用程序。硬件诊断功能 。
136、 硬件控制从特定位置(例如闪存)开始加载BIN文件(ELF文件中提取的),BIN引导加载器。
137、 任务调度。需要了解操作系统源码。
138、 在嵌入式系统中,任务间同步与通信的方法主要有信号量、 互斥锁、事件和消息队列 。固定的模式代码。优先级反转,优先级继承。
139、 递归锁,解决互锁问题、多次上锁。造成死锁的根本原因,是由多个任务对同步对象的获取顺序不一致而造成的。如果所有的任务在需要持有多个同步对象时总是采用相同的获取顺序,就一定不会出现死锁问题 。
140、 事件。消息队列。应该属于平台框架代码模式,常见的数据结构和算法,需要统一实现。
141、 内存管理分为两个大类:堆管理、内存池管理。从堆中分配内存是按用户所需大小进行的 ,内存池是采用固定缓冲区大小的方式。可以两者结合。
142、 结构体中两个变量互反,用于预防内存溢出篡改。尾部放置标识防止写溢出。
143、 内存池,将内存按照8、16、32、64等大小分类管理。减少内存碎片。
144、 用枚举替代__FILE__信息。
145、 设备分成三大类 : 字符设备、块设备和帧设备(有的称为网络设备〉 。字符设备的数据以字符流形式被访问,如串口、键盘。块类型设备能够随机访问固定大小的数据片,如硬盘、间存。帧设备是一帧一帧发送和接收数据包的,如以太网接口 。
146、 字符设备的五个函数:open、close、read、write、control。设备和中断、安装驱动,设备注册。
147、 用循环链表(13个桶循环)管理定时器。
质量保证
148、 质量=需求分析、设计、编码、验证。必要的流程、合适的工具、文档、笔记、持续学习、技术敏感性等。
149、 判断false分支,减少{},减少相关代码距离。
150、 用sizeof()减少错误,减少关联代码,避免潜在错误。
151、 Goto适合错误处理。不能形成环。
152、 利用全局静态数组减少内存申请和管理。
153、 逆序释放内存,减少因为依赖导致的崩溃
154、 对外接口需要检查参数有效性。对内接口可以用assert替代。有些将有效性判断交给用户解决。
155、 利用语言特性优化,例如:static const char cT[]=”xxx”;sizeof(cT);chat temp[]={0};
156、 允许重复初始化、重复释放,减少调用陷阱。
157、 减少锁的粒度。时间维度、资源维度都需要减少。
158、 只包含必要的头文件。尽可能不要在头文件中包含其他的头文件 ,取而代之的是尽量在.c源程序文件中包含它们。
159、 对外头文件尽量简化。只在c文件中定义私有类型。C文件包含私有头文件。
160、 只对外暴露必要的变量和函数。
161、 消除所有告警。
162、 单元测试:写代码测试函数、类等。类似预研代码。构造测试条件、调用被测函数、检查测试结果。利用宏简化代码。
163、 利用单元测试框架、库、规则,实现对代码的管理和自动测试。
164、 桩函数就是一个虚假的函数实现。
165、 Gcov检查代码覆盖、lcov
166、 Pc-lint静态分析,makefile中整合lint(linux下wine环境)
167、 Valgrind动态分析、callgrind性能分析、kcachegrid有UI


http://www.ngui.cc/article/show-861236.html

相关文章

Kaggle系列之预测泰坦尼克号人员的幸存与死亡(随机森林模型)

Kaggle是开发商和数据科学家提供举办机器学习竞赛、托管数据库、编写和分享代码的平台&#xff0c;本节是对于初次接触的伙伴们一个快速了解和参与比赛的例子&#xff0c;快速熟悉这个平台。当然提交预测结果需要注册&#xff0c;这个可能需要科学上网了。我们选择一个预测的入…

最新整理Spring面试题2023

Spring面试专题 1.Spring应该很熟悉吧&#xff1f;来介绍下你的Spring的理解 有些同学可能会抢答&#xff0c;不熟悉!!! 好了&#xff0c;不开玩笑&#xff0c;面对这个问题我们应该怎么来回答呢&#xff1f;我们给大家梳理这个几个维度来回答 1.1 Spring的发展历程 先介绍…

【嵌入式】MDK使用sct文件将代码段放入RAM中执行

sct文件即分散加载文件&#xff0c;是ARMCC编译器使用的链接脚本文件&#xff0c;等同于GCC编译器的ld链接脚本。MDK IDE使用的是ARMCC。 支持NorFlash中运行代码&#xff08;XIP&#xff09;的MCU例如STM32&#xff0c;一般将所有代码&#xff08;text段&#xff09;都放在FL…

Word控件Spire.Doc 【Table】教程(10): 如何在 C#、VB.NET 中将嵌入式 Excel 工作表转换为 Word 表格

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

Python Fiddler抓包工具教学,获取公众号(pc客户端)数据

前言 今天来教大家如何使用Fiddler抓包工具&#xff0c;获取公众号&#xff08;PC客户端&#xff09;的数据。 Fiddler是位于客户端和服务器端的HTTP代理&#xff0c;是目前最常用的http抓包工具之一。 开发环境 python 3.8 运行代码pycharm 2021.2 辅助敲代码requests 第三方…

HTTP 框架 Hertz 初体验

目录版本预配置安装 Golang环境配置安装命令行工具 hz生成/编写示例代码运行示例代码引用附加资料注脚版本预配置 VMware 配置 CentOS 7 64位,参考 链接Golang 下载 go1.17.linux-amd64.tar.gz PS : 不要下载 go 1.20 的新版本,因为有些东西暂不支持会报错1 安装 Golang 将 …

PCI驱动程序框架

PCI驱动程序框架 文章目录PCI驱动程序框架参考资料&#xff1a;一、 PCI驱动框架二、 RK3399驱动致谢参考资料&#xff1a; 《PCI Express Technology 3.0》&#xff0c;Mike Jackson, Ravi Budruk; MindShare, Inc.《PCIe扫盲系列博文》&#xff0c;作者Felix&#xff0c;这是…

shell 脚本编程 九:总结

一、特别说明 Shell 是弱类型的语言&#xff0c;在 Shell 中所有的变量默认都是字符串型。 二、数据类型 1、字符串&#xff1a;字符串可以用单引号&#xff0c;也可以用双引号&#xff0c;也可以不用引号&#xff08;建议使用双引号&#xff0c;因为双引号里可以有变量和特…

LeetCode每日一题(332. Reconstruct Itinerary)

You are given a list of airline tickets where tickets[i] [fromi, toi] represent the departure and the arrival airports of one flight. Reconstruct the itinerary in order and return it. All of the tickets belong to a man who departs from “JFK”, thus, the…

LeetCode 刷题系列 -- 124. 二叉树中的最大路径和

路径 被定义为一条从树中任意节点出发&#xff0c;沿父节点-子节点连接&#xff0c;达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。路径和 是路径中各节点值的总和。给你一个二叉树的根节点 root &…