打印
[技术问答]

Keil优化等级与volatile

[复制链接]
166|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xiaoyaodz|  楼主 | 2023-3-15 11:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
为了最大限度的使用单片机(处理器)的存储资源,往往需要开启代码优化功能,这样能够使代码更紧凑,生成的Bin文件(二进制文件)较小,占用更小的存储空间。
不同的编译环境(IAR、Keil、eclipse等)生成的二级制文件是不同的,相同编译环境的优化等级以及优化程度不同,生成的二级制文件也是不同的。如下Keil编译器,分为四个优化等级。-O0、-O1、-O2、-O3。
这四个优化等级代表什么意思呢?
-O0:是编译器默认级别。关闭大多数优化,但一些简单的源转换除外。对编译的二进制文件的性能执行最低限度的优化。此选项提供了最佳的调试效果。
-O1:限制优化。提供了一个总体上令人满意的调试效果,具有良好的代码密度。
-O2:高优化。调试效果可能不太令人满意,因为目标代码到源代码的映射并不总是清晰的。编译器可能会执行调试信息无法描述的优化。
-O3:最大优化。此选项通常提供较差的调试效果。
优化等级越高调试效果越差,Debug的时候单步执行会有“跳跃感”,感觉代码不是按照自意图跑。而且有时候开了优化之后会发现一些莫名其妙的问题,比如延时时间时间不准了,程序崩溃了等等。另外,开不开优化最好是项目初期就确定下来,防止所谓的“莫名其妙”的问题出现。项目基本开发完了再提高优化等级往往会出问题。
其实这些问题并不都是优化导致,而是编码不规范所致,不能完全归结于优化。调试的多了就会发现一般不开优化没有问题,开优化就会出问题,往往和全局变量有关系。这时候就要用到C语言的volatile关键字。
一般情况下线程之间共享的全局变量定义时需要加上volatile关键字,主程序和ISR中共享的全局变量也应该加上。当使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。
如下示例代码:

volatile int i=100;void thread1(void){    int a,b;          ...     a = i;     ...    // 在此处其他线层或者ISR,修改了i值     b = i;     ...}void thread2(void){    i = 10;}
thread1中:如果开了优化,并且没有volatile定义i,编译器有时会先把变量读取到一个寄存器中,再取变量值时,就直接从寄存器中取值。由于编译器发现两次都是从 i读数据,而且两次读取之间没有对i进行修改,编译器会自动把寄存器中的值赋值给b,而不是重新从i的原地址处读取。编译器不知道在两次赋值之间其它线程或者ISR可能会修改i。如果有了volatile定义,那么编译器每次会从i的内存地址存取数据,保证数据的正实时确性。

使用特权

评论回复
沙发
tpgf| | 2023-4-10 08:20 | 只看该作者
共有9个优化级别(书上这么写的),高优化级别中包含了前面所有的优化级别

使用特权

评论回复
板凳
qcliu| | 2023-4-10 10:48 | 只看该作者
0级优化:
1、 常数折叠:只要有可能,编译器就执行将表达式化为常数数字的计算,其中包括运行地址的计算。
2、 简单访问优化:对8051系统的内部数据和位地址进行访问优化。
3、 跳转优化:编译器总是将跳转延至最终目标上,因此跳转到跳转之间的命令被删除。

使用特权

评论回复
地板
drer| | 2023-4-10 11:19 | 只看该作者
优化级别并非越高越好,应该根据具体要求适当选择

使用特权

评论回复
5
coshi| | 2023-4-10 11:53 | 只看该作者
有一个优化登记是死码消除:无用的代码段被消除。那么keil如何判定代码是无用的呢  有标准吗

使用特权

评论回复
6
kxsi| | 2023-4-10 12:15 | 只看该作者
这些优化等级 他们优化的规则是如何定义的呢

使用特权

评论回复
7
wiba| | 2023-4-10 13:15 | 只看该作者
有一个等级的优化是将冗余的MOV命令去掉,那如果是 使用c语言编程 是不是就不存在mov的命令了呢

使用特权

评论回复
8
LOVEEVER| | 2023-4-11 14:12 | 只看该作者
优化过高也不全是好事

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

4554

帖子

2

粉丝