如何优化代码

缩小编译代码 size 的几种方式:

(A) 逻辑与算法:

合理的工作逻辑与算法. 一般而言, Code 永远是工程师的逻辑思维的体现. 无论是实现 function target or 构建 system struction, 逻辑思维的能力高低, 对 code size 具有深度影响(甚至对整个 project 的成功实现, 具有决定性的影响).

(B) 编译器的配置:

1. 将编译器的 size 优化调整到 high级别.

2. 如果我们是 arm 的 user, 应选择 Thumb mode, 而不是 Arm mode.

我们无意在这里讨论16-bit thumb指令集 与 32-bit arm 指令集有何具体异同. 我们仅仅从 mcu 的datasheet 中寻找到如下解释(讨论了两者最终表现力): “工作在与 arm mode 相同的 32-bit 寄存器上, thumb code 保持了绝大部分的 arm 的表现力(的同时), Thumb code能够提供高达 65% 的(作为比较的)arm code size.”

(C) 谨慎使用任何标准/编译器提供的 C Library function:

谨慎使用编译器提供的任何C Library function, 如果必需, 尽量自行完成需要的函数功能.

1. 谨慎使用string相关函数

无论是 sprintf(), atoi(), ntop(),都会带来size 的显著增加. 如有可能, 我们应当自行完成我们需要的类似的 functions.

2. 谨慎使用 time 相关函数: 举例说 localtime(), etc 等函数.

3. 谨慎使用 math 函数, 尽量不要包含 math.h
作为两个比较的的例子是, 在同等编译条件下, fasbs()可能多耗费 about 200bytes. sqrt() 可能会多耗费 about 3.5k bytes.

(D) 数据类型与编程习惯

1. 尽量避免 char(U8/S8), short(U16/S16) 的定义, 而使用 int(U32/S32) 的定义.

对于从 8-bit来到 arm world 的 engineer, 可能份外不习惯这个转变吧?

C/C++ compiler reference document 明确指出: 只要可能, 就应使用 int or long 来替代 char or short, 从而避免了符号位扩展与zero拓展. 而且, 对 loop index 使用 int/long 将减小 code 产生. 特别要指出, 在 thumb mode, stack pointer(SP) 被严格定义为 32-bit data types(因此更应该使用 int/long).

一个令人有兴趣的简单实验能够证明, 所谓的”sign extension or zero extensize”带来的额外代码消耗. 在一份c的源文件中, 如果我们定义了 U8 global_data. 简单将其改为 U32 global_data. Then do rebuild all, we will find the code size decrease 4 bytes… ; ) 但是要提及的是, 我们的项目经验说明这个way往往还会带来一个其他的效果: DATA size在这种情形下或略有增加.

2. 尽量避免使用带符号位的数据类型.

3. 尽量避免 long(8-byte) 的定义.

4. Bitfields 与 packed structures 将产生大而且慢的代码.

对于 packed structures, 作者在相同的 blog 主页发表了专题文章, 指出了选择使用 packed structures, 仍然可以享受到尽可能小的 code size, 以及保持access speed的处理方式. 检索作者的 blog, 或检查全部文章列表, 将会发现该篇文章. 在我们的项目经验中, 在 32k bytes 左右的 project 中, 我们获得了额外的大约 2k bytes 的节省的 code size.

5. 尽量不要定义 float, double.

在一些运算中, 我们常常将牵涉到如下步骤: 将float *10e(小数点后位数), 将float转化为U32进行运算. 结果在/10e(相应位数). 运算精度在这里被降低了. 但这完全取决于我们的工作目标: 在不复杂的算法中, 避免了浮点运算的使用(以上讨论, 均假设我们的 mcu 不包含浮点运算协处理器). Reference 也一再强调没有math协处理器, 浮点数据类型效率低下.

6. reference 指出, 尽量定义 local 变量. 减少 static 或 global 变量的定义, 这样将帮助优化的过程. 且local 变量尽量少使用 &. Reference 指出, 这种定义将放置变量到 memory 中, 而不能放置到处理器的 register 中(代码会变大变慢). 另外也不能有助于优化器进行优化.

7. *(2的倍数), 或 /(2的倍数), 使用 “<<” 以及 “>>” 操作.

8. 应保持数据变量的type 定义的一致性, 在运算中, 尽量减少类似 U32 -> U16 -> U32 的不必要的强制转化过程.

9. 定义字符串为全局变量, 在 ram 富余的情况下, 这是一个利用 ram 来分担降低 code size 的技巧.

构建代码的过程, 不仅仅是理性思维落实为真实世界逻辑的过程, 我们觉得, 也是和编译器进行交互的过程. 我们所作所为, 需要实现目的之逻辑, 我觉得也需要, "讨好"编译器, 让它为我们的代码, 生产 size 和 speed 都得到优化的job.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值