嵌入式开发易错点及开发技巧总结(持续更新)

发布时间:2024年01月06日

目录

前言

易错点总结

1、关于浮点数比较及交换

2、关于strlen()使用

3、关于自动转换规则

4、关于数据类型长度

5、关于字长

开发技巧总结

1、数据取余

2、宏的高级用法

前言

????????本篇内容主要列举一些自己在嵌入式开发过程中踩过的大坑(还有平时收集的一些易错点),希望能对遇到类似问题的开发者有所启发。

易错点总结

1、关于浮点数比较及交换

? ? ? ? 第一次碰到这个问题是在刚毕业面试那会,当时有一个面试题:怎么判断一个float类型数据是否为0?一开始看到这个问题的时候还真没当回事,不就 return (f == 0);就完事了吗?结果可想而知。现在回过头来看,确实这个回答略显业余。

 void main()
 {
      float x =1.2; float y = 3.2;
      if((x + y)==4.4)  {  printf(“correct\n”);  }
      else  {  printf(“ error \n”);  }
 } 

结果是error!!!浮点数是为了能用二进制表达小数而引入的一种量化形式,转换时存在舍入差,因此不能直接用“==”比较浮点数,正确的做法应该是确定一个误差范围,通过比较两个浮点数的差值是否在这个误差范围内来判断是否相等。

 const float delta = 0.1
    void main()
    {
      float x =1.2;  float y = 3.2;
      float z = x + y;
      if((z < (4.4+delta))&&(z > (4.4-delta))) {  printf(“correct\n”);  }
      else  {  printf(“ error \n”);  }
    }

那么很显然判断一个float数据是否等于0应该是如下表达

int isZero(float data)
{
    //float类型一般精确到小数点后5位或6位
    return(data > -0.000001 && data < 0.000001);
}

2、关于strlen()使用

如下列代码所示

/*判断一*/
if(strlen(x)>= strlen(y))
{
}
/*判断二*/
if(strlen(x)- strlen(y)>= 0)
{
}

????????从表面上看,上面的两个判断表达式“完全相等”,但实际情况并非如此。其中,判断表达式一没什么问题,程序也能够完全按照预想的那样工作; 但判断表达式二的结果就不一样了,它将永远是真,这是为什么呢? 原因很简单,因为函数 strlen 的返回结果是 size_t 类型(即无符号整型)而 size_t 类型绝不可能是负的。因此,语句“if(strlen(x)-strlen(y)>=0)”将永远为真。

3、关于自动转换规则

? ? ? ? 这个问题是在几天前碰到的,类似代码如下

unsigned char foo(void)
{
    unsigned int a = 6;
    int b = -20;
    return (a+b > 6);
}

以上函数返回值为真!原因:当表达式中同时存在有符号类型和无符号类型时,所有的操作数都自动转换为无符号类型上式中-20会被自动转换为一个非常大的正整数,所以结果会远远大于6。(如果这个问题出现在上大学那会,我想肯定不会出错,其实很多问题的解决方法往往是最基础的理论知识,像运算符优先级、自动转换这些概念往往容易出现问题,但却都是最基础的代码规则,所以大家在写代码时切勿眼高手低,遇到拿不准的地方及时巩固)

4、关于数据类型长度

? ? ? ? 还是一个面试,当时面试官问我:int类型数据占用几个字节?4个字节!接着他问我确定吗?我犹豫了,因为我觉得他不会问这么简单的问题!那是不是就要分情况分析?不同编译器、不同位数的处理器是不是就不一样?我们常用的处理器都是32位,int类型默认占用4个字节,那如果是64位处理器是不是就是8个字节?float类型是不是也会有变化?究其原因还是对底层概念的模糊。

? ? ? ? 那么今天在这里做一个简单的归纳:数据类型的长度与编译器规则密不可分,尽管同样的类型在不同位数的系统上所代表的位数也可能不同,但是总归是有一些规则约束的。编译器可以根据自身硬件来选择合适的大小,但是需要满足约束:short和int型至少为16位,long型至少为32位,并且short型长度不能超过int型,而int型不能超过long型。这即是说各个类型的变量长度是由编译器来决定的,下面列举在GCC编译器下16位机器、32位机器和64位机器各个类型变量所占字节数:

C类型163264
char111
short int222
int244
long long888
char*248
float444
double888

5、关于字长

? ? ? ? 字长涉及到的易错点有很多,数据的字节对齐、结构体数据的步进值、指针移位等等,但这些相信大家平时接触的都比较多,这里不再详细列举,请看下列示例

unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */

如上代码,在一个int类型不是16位的处理器中表达就是不正确的,应该表示为

unsigned int zero = 0;
unsigned int compzero = ~0;
/*1's complement of zero */

(在单片机中,常采用“一补”(1's complement)格式,也即在16位处理器中,0xffff就是0,在32位单片机中,0xffffffff就是0;在手机端或者电脑端一般采用“二补”(2's complement),即0xffffffff就是-1)

开发技巧总结

1、数据取余

value % x 等同于 value & (x-1),仅限于对偶数取余

2、宏的高级用法

????????使用场景:假如我们有很多种动物(猫,狗,鸡等等),都需想用一个结构体来定义,再假如结构体都只想描述动物的重量和身高,但又不想所有动物的结构体名称一致。假如结构体都想用Animal_打头,如Animl_Cat,同样我们用宏定义来实现:

#define StructureType(type)                           typedef struct{ \
                                                            float weight; \
                                                            float height; \
                                                        }Animal_ ## type;
使用:
StructureType(Cat);// 定义一个Animl_Cat结构体
Animal_Cat cat;// 实例化一个Animl_Cat
cat.weight = 10;
cat.height = 30;

你可能在想,我想定义一个新的动物结构体,增加一个动物属性,那就结合上面的组合方式
#define StructureTypeEx(type, member)                  typedef struct { \
															float weight; \
															float height; \
															char* ## member; \
														}Animal_ ## type;

使用:
StructureTypeEx(Dog, Name);// 定义了一个动物名
Animal_Dog dog;
dog.height = 60;
dog.weight = 100;
dog.Name = (char *)malloc(32);
memset(dog.Name, 0, 32);
strcpy(dog.Name, 7, "HuaHua");

文章来源:https://blog.csdn.net/qq_56527127/article/details/135405745
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。