方法之一么,就是把for延迟的函数单独放到一个文件里,设置该文件优化等级为-00来编译。 不过我在这个例程里不使用这个方法。看一下下面这个实验代码(不是试验,因为linux的内核代码里就有这个用法,我照搬了^_^) std=gnu99 -0s /* main.c 就这一个文件,最高优化*/ #include <avr/io.h> uint8_t t1=127; uint8_t chgt1(void) { t1=0; if(t1>5) //这里的判断会被优化掉 { t1=6; } asm volatile("":::"memory"); //这句就是“D版”自linux内核代码的^0^,空语句,不增加额外代码 if(t1>0) //但这里就不会被优化了 { t1=5; } return t1; } uint8_t status() { return PINB; } void mydl(uint8_t tm) __attribute__ ((noinline)); //不设置noinline属性的话,会被gcc内联到每个调用语句处的,空间换时间的优化 void mydl(uint8_t tm) { for(uint8_t i=tm;i!=0;) { asm volatile(""); //这句是根据avrgcc改的 i--; } } void test(void) { uint8_t tmp; tmp=t1; do{ t1++; mydl(t1); //延迟 tmp=status(); }while(tmp&0x80); } int main(void) { test(); mydl(t1); //延迟 t1=chgt1(); while(1); return 0; } linux内核代码中有个概念叫“内存屏障(Memory barriers)”,在x86上实现该屏障功能的宏之一是wbm(),展开就是asm volatile("":::"memory"); memory属性使gcc编译时认为,到这句时内存里内容发生变化了,不能使用寄存器中的值了(类似于t1设置了volatile属性)。 由于这句的存在,第二处的判断就没有被优化掉。 asm volatile("");相当于强行插入一个汇编代码(虽然也是空代码),打断了对这个循环的优化策略,使gcc只能照实际代码编译了。 另外,测试了下,在avrgcc下,asm后面不写volatile好像也没关系,不过写了比较保险:)。 //使用方法 mydl(1000); //延迟 void mydl(unsigned int tm) __attribute__ ((noinline)); //不设置noinline属性的话,会被gcc内联到每个调用语句处的,空间换时间的优化 void mydl(unsigned int tm) { for(unsigned int i=tm;i!=0;) { asm volatile(""); //这句是根据avrgcc改的 i--; } } |