[资料分享] 单片机开发时,常见的C语言错误点

Aguilera   2020-5-9 21:38 楼主

在进行单片机开发时,经常都会出现一些很不起眼的问题,这些问题其实都是很基础的c语言知识点,是一些小细节。但是正是因为很基础,又都是小细节,所以我们往往容易忽视它们。结果有时候我们会花很长的时间纠结一个问题,迟迟找不到问题的所在。当发现原因竟然是这么的简单和不起眼时,大家都会感到痛不欲生。

1. !和 ~ 不一样

  ! 是逻辑非符号,~ 是位取反符号。

  对IO口某个管脚赋值时不要错用 !,如

LCD_CS_n_DR &= !LCD_CD_n_MASK;  //错误  
LCD_CS_n_DR &= ~LCD_CD_n_MASK;  //正确  

2.<<和>>的优先级低于+、-

比如要实现c=x*2+1,没有加括号会出错

c = x<<1+ 1;      //错误,c=x*(1+1)  
c = (x<<1) + 1;   //正确,c=x*2+1  

3.移位要防止溢出

其实用移位代替乘除法是个不错的方法,笔者很喜欢拿到一段代码后用移位代替乘除法来进行优化。不过有时候却会出现问题,比如溢出问题。当很明显可能溢出的话我们是会注意的,比如

char m = c<<4;    //c为char型,可能溢出  

但是有时候这个问题是不明显的,比如当移位出现在数组索引或函数参数时,有段用液晶显示字符的代码如下

char m = Font8x16[c*16+1]; //c为字符,寻找c的点阵字库  

我们可以用左移运算来代替乘法进行优化,如

char m = Font8x16[(c<<4)+1];  //c为字符,寻找c的点阵字库  

这本是一个好方法,但是事实上上面的代码是错的。当执行c<<4时,因为没有明显的赋值过程,我们可能认为没问题,而事实上c的高位已经丢失了,所以得到错误的结果。一个可行的做法是先进行强制转换,如

char m = Font8x16[(uint16)c<<4)+1];   //c为字符,寻找c的点阵字库  

4.无符号数和有符号数混合运算都会被强制转换为无符号数运算

当一个有符号数和一个无符号数进行算术运算时,系统会自动将有符号数强制转换为无符号数再进行运算(即使你使用有符号数强制类型转换),如下面两种写法的运输结果是一样的

char a = (unsigned char)b / (signed char)c;  
char a = (unsigned char)b / (unsigned char)c;  

5.局部变量要初始化

局部变量没有初始化的话,如果单片机每次为他分配的是同一个内存区域,当你在函数中是这么使用局部变量时,就可能出问题:

void fun(char a)  
{  
  char b;
    if(a==0)  
        b = 2;
}  

如果第一次调用fun时,a传递的值为0,那么b = 2;以后再调用fun时,即使a不为0,但如果b依然使用之前的内存区域,那么其值一直为2。

如果要避免这个错误,平时要养成对局部变量初始化的习惯。

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复