忘记在哪里摘抄的笔记,总结一下。
不同的数据类型所生成的机器代码长度相差很大,变量类型选取的范围越小运行速度越快,占用的内存越快。
比如,能用char型的变量,就没必要使用int型来定义;能用int型的变量,就没必要使用long int型来定义;能不使用float型,就不用。能用unsigned int型的变量,就没必要使用int型来定义;
因为有些处理器处理无符号比处理有符号更有效率。使用float类型,需要借助FPU(浮点运算单元)或者浮点型运算库,而int型可以直接被处理器运算。
注:在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C编译器并不会报错,但程序运行结果此时已经错了。
算法优化指对程序时空复杂度的优化。
在PC机上进行程序设计时一般不必过多关注程序代码的长短,只需考虑功能实现。但在嵌入式系统上,就必须考虑系统的硬件资源。
在程序设计时,在不影响程序功能的需求下,应考虑代码尽可能短的算法。
函数调用要使用系统的栈来保存数据,同时CPU在函数调用时需要保存和恢复当前的现场,进行对栈的push和pop操作,所以函数调用实际上也需要CPU时间。
宏定义仅仅作为预先写好的代码嵌入到当前程序上,不产生函数调用,所占用的仅仅是一些空间,省去了参数压栈,生成汇编语言的call调用,返回参数,执行return等过程,从而提高程序的执行速度。
程序上对时间要求苛刻的部分可以用内嵌汇编来重写,提高执行速度。汇编较难,慎重使用。
在多重循环中,尽量不超过三层循环。
在多重循环中,应将最长的循环放在最内层,最短的循环放在最外层。这样可以减少CPU跨切循环的次数。
- int i=0,j=0;
- for(i;i<10;i++) //效率高于下方
- {
- for(j;j<30;j++)
- {
- }
- }
-
- for(j;j<30;j++) //效率低于上方
- {
- for(i;i<10;i++)
- {
- }
- }
while(1)和for(;;)起一样效果,无限循环。
while(1)编译后
- mov eax,1
- test eax,eax
- je foo+23h
- jmp foo+18h
for(;;)编译后
jmp foo+23h
for(;;)指令少,不占用寄存器,而且没有判断,跳转。CPU效率上比while(1)好。
当switch语句的case标号很多时,为了减少比较的次数,可以把发生的频率性相对高的条件放到第一位或者把整个switch语句转化为嵌套switch语句。把发生频率高的case标号放在最外层的switch语句中,发生频率较低的case标号放在另外的switch语句中。
如,把发生频率高的case标号放在最外层的switch语句中,发生频率较低的case标号放在缺省(default)的内层switch语句中。
- switch (表达式)
- {
- case 值1:
- 语句1;
- break;
- case 值2:
- 语句2;
- break;
- ……
- /*把发生频率低的放在内层的switch语句中*/
- default:
- switch (表达式)
- {
- case 值n:
- 语句n;
- break;
- case 值m:
- 语句m;
- break;
- ……
- }
- }
使用C语言标准库可以加快开发速度,但由于标准库需要设法去处理用户所有遇到的情况,所以很多标准库代码很大。
比如,标准库的sprintf函数非常大,很大一部分用于处理浮点数,如果程序中不需要格式化浮点数值,程序设计人员就可以根据实际情况用少量的代码实现这个功能。
乘法比除法更有效率,移位比乘法更有效率。
a=b*2 -> a=b<<1;
a=b/4 -> a=b>>2;
a=b%8 -> a=b&7;
a=b/8*8+b%4 -> a=((b>>3)<<3)+(b&3);
a=b*15 -> a=(b<<4)-b;
由于成本限制,嵌入式系统存储器容量有限。程序上所有的变量,包含的库函数以及堆栈等都使用有限的内存。
全局/静态变量进入main函数之前就被创建,生命周期为整个源程序,存储在全局/静态存储区。
局部变量,在栈中分配。在函数被调用时才被创建,生命周期为函数内。
因此,在程序中应尽量使用局部变量,提高内存使用效率。
程序中堆大小受限于所有全局数据和栈空间都分配后的剩余量。如果堆太小,程序就不能够在需要的时候分配内存。
因此在使用malloc函数申请内存之后一定要用free函数释放内存,防止内存泄漏,造成内存碎片。
考虑Fibonacci(斐波那契)问题,Fibonacci(斐波那契)问题是可以通过简单的递归方法来解决。
- int fib ( n )
- {
- if ( n == 0 || n == 1 )
- {
- return 1;
- }else
- {
- return fib( n - 2 ) + fib ( n - 1 );
- }
- }
注:考虑Fibonacci(斐波那契)系列从1开始,因此,该系列看起来:1,1,2,3,5,8...
从递归树,我们计算fib(3)函数2次,fib(2)函数3次。这是相同函数的重复计算。如果n非常大,fib函数的效率会比较低。
Memoization是一个简单的技术,可以被用在递归,加强计算速度。fibonacci 函数Memoization的代码如下:
- int calc_fib ( int n )
- {
- int val[ n ] , i;
- for ( i = 0; i <=n; i++ )
- {
- val[ i ] = -1;
- }
- val[ 0 ] = 1;
- val[ 1 ] = 1;
- return fib( n , val );
- }
-
- int fib( int n , int* value )
- {
- if ( value[ n ] != -1 )
- {
- return value[ n ];
- }else
- {
- value[ n ] = fib( n - 2 , value ) + fib ( n - 1 , value );
- }
- return value[ n ];
- }
如利用DMA传输方式减少中断次数,因为DMA传输没有用到CPU,而中断用到CPU。