为了最大限度的使用单片机(处理器)的存储资源,往往需要开启代码优化功能,这样能够使代码更紧凑,生成的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的内存地址存取数据,保证数据的正实时确性。
|