极品的C语言错误

今天在测试硬件通信模块时候发现一个奇怪的问题,发送数据和接收数据进行比较复制时候频繁数据错误。

测试流程如下:发送一个字节和接收一个字节,进行比较,当返回数据和发送数据不相等的时候,错误计数器累加。

数据收发抽象如下:

uint16 i = 0;

uint16 j = 0;

uint32 error_num = 0;

XX_send_data(i++);

j = XX_rece_data();

if(i != (j + 1)) {

error_num++;

}

这段代码按照理论上来说,只要发送数据i和接收数据一样,那错误计数器应该不会出错,但是实际上出错了,最开始怀疑是由于FPGA硬件模块数据发送和接收时序有问题,但是多次大批量功能仿真以及时序仿真都没问题。

这下我就开始怀疑这段短小的C程序是否工作正常,因此,

在error_num++这句话这里打断点,查看每次出错数据都是i=0,j=65535的时候出错,为什么会全部出错在这里呢?

百思不得其解,后来询问资深工程师飞哥,飞哥一看就看出问题出现在哪里了,让我汗颜呀!!~~

原来错误是这样发生的:(程序运行在32位处理器)

这段程序从表面上看是没有任何问题的,但是细致分析就会发现,当i=65535发送数据,发送完成后执行i++,i此时变为0,j调用接收函数后,返回值正确也是65535,但是,那看来问题就出现在if(i != (j+1))这里了。

原来, j+1 这种算术运算的运算值是默认存到32寄存器中,因此j+1运算结果为32位数据,因此,当j=65535时候,(j+1)实则为65536,(0 != 65536),因此产生不匹配。错误码自加。

有很多种方法消除这种错误,修改代码如下即可解决问题。

uint16 i = 0;

uint16 j = 0;

uint32 error_num = 0;

XX_send_data(i++);

j = XX_rece_data();

if(i !=(uint16)
(j + 1)) {

error_num++;

}

终于找到问题了,看来以后写代码还得仔细了,吸取教训。

  // 看了回复,发现很多人都以纯软件的方式来理解这段代码,但是嵌入式C语言里面一定要详细和处理器行为结合起来,以下添加详细解释

  这张截图为这段代码对应的汇编代码,详细阅读这段汇编代码即可找出问题所在。

  

  第一句汇编代码ldhu r3,-10(fp)  意思为从内存或者cache中加载一个半字,并且扩展成无符号类型,这句话就是把变量i加载到寄存器R3中,R3为32位寄存器,这时候虽然变量i为uint16但是比较的时候还是变成了32位

  第二句汇编代码ldhu r2,-12(fp)  同上一句话一样,这里是加载变量j到寄存器R2中

  第三句汇编代码addi r2,r2,1    /*问题所在*/  这句话就是执行的j+1,可见结果是保存在r2中,r2为32位宽的寄存器,所以当i=0,j=65535时,j+1
= 65536并未溢出,而是直接赋值给r2,此时r2即为65536,r3为0

  最后一句汇编代码 beq r3,r2,0x800258<main+92>这句话是比较r3和r2的值,如果相等就跳转到0x800258<main+92>这个地址执行程序。如果不相等就直接运行下一句语句,也就是error_num++

  从上面的分析看出,嵌入式行业一定要对处理器非常熟悉,出现些稀奇古怪的问题,才能最终找到问题所在。

时间: 2024-12-19 23:12:48

极品的C语言错误的相关文章

C语言-错误处理

标记程序的运行状态和控制主要有以下几种:break/continue/return/参数的返回值/exit(int n)_exit() atexit((*p)(参数列表)): 1 break:用在开关语句.循环语句.和if结合使用.表示跳出当前开关.循环体(仅跳出一层),执行开关循环体后面的程序,和if结合使用表示满足条件则结束循环.注意break对if else不起作用,在多次循环中只能跳出一层. 2 continue:用在循环体.和if配套使用.表示结束本轮循环强制进行下一轮循环.和if结合

Go语言开发(七)、Go语言错误处理

Go语言开发(七).Go语言错误处理 一.defer延迟函数 1.defer延迟函数简介 defer在声明时不会立即执行,而是在函数return后,再按照FILO(先进后出)的原则依次执行每一个defer,一般用于异常处理.释放资源.清理数据.记录日志等.每次defer语句执行时,defer修饰的函数的返回值和参数取值会照常进行计算和保存,但是defer修饰的函数不会执行.等到上一级函数返回前,会按照defer的声明顺序倒序执行全部defer的函数.defer所修饰函数的任何返回值都会被丢弃.如

C语言错误:request for member ‘xxx’ in something not a structure or union

今天在编译一个C语言程序时,对于结构体变量,报出错误 Error: request for member 'xxx' in something not a structure or union. 经过调试发现是 . 与 -> 搞错了. 如果它是地址,就在它后边用 ->,如果它不是地址,就在它后边就用 . 代码举例简略如下: #include <stdio.h> #include <string.h> typedef struct Test_t { char name[2

C语言错误处理

学习C++的时候就没有怎么重视异常这部分知识,后来知道也基本没有看到C++项目里面用try/catch的.google编程规范中甚至直接说明不使用C++这个特性,所以我一直都没搞明白这个"简单的"try/catch. 查阅<C++编程思想>,我记录以下一些内容.首先是C语言的一些错误处理方法. 1) 出错信息可通过函数的返回值获得.如果函数返回值不能用,则可设置一全局错误判断标志(标准 C语言中 errno( )和perror( )函数支持这一方法).由于对每个函数调用都进

C语言错误: CRT detected that the application wrote to memory after end of heap buffer

CRT detected that the application wrote to memory after end of heap buffer 多是中间对其进行了一些操作,在程序结束处,释放内存的时候,引起错误: HEAP CORRUPTION DETECTED:after Normal block(#***) at 0x****.CRT detected that application wrote memory after end of heap buffer. 错误原因: 以对内在操

C语言错误: HEAP CORRUPTION DETECTED

程序源代码: //写文件两种方式(文本文件和二进制文件) #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> //文本写文件 int writeWord(const char *path,const char *pword){ int ERRO_MSG = 0; if (path == NULL) { ERRO_MSG = 1; printf(&q

Go语言错误处理小例子

满屏的error处理会是个悲剧,也不利于对错误进行区分处理. 建议在项目中多用自定义错误,再对错误集中处理. package main //error处理方式演示 //author: Xiong Chuan Liang //date: 2015-2-26 import "fmt" import "errors" func main() { errType(test0()) errType(test1(" test1 ")) errType(tes

C语言错误解析---关于结构体问题

问题描述:error C2224: left of '.err' must have struct/union type 分三块来讲述: 1 首先://注意在C和C++里不同 在C中定义一个结构体类型要用typedef: typedef struct Student { int a; }Stu; 于是在声明变量的时候就可:Stu stu1;(如果没有typedef就必须用struct Student stu1;来声明) 这里的Stu实际上就是struct Student的别名.Stu==stru

43&gt;&gt;c语言错误信息

1. warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration] warning: incompatible implicit declaration of built-in function ‘malloc’ [enabled by default] (矛盾的 含蓄的) reason: 使用malloc时没有包含库stdlib.h method: 添加库咯 2. undefined r