AVR studio 编绎警告[Warning] left shift count >= width of type导致数据出错问题分析

项目场景:

一个具有使用本地数据保存的产品,在测试过程中发现数据超过65535字节时,读取数据记录的数据字节数不对,总是丢失高16位的记录数.


问题描述:

问题代码如下: 

uint32_t EEread_DataAdd(void)
{
    uint8_t temp[4];
    uint16_t high,low;
    uint32_t ndata;

    temp[0] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr);
    temp[1] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 1);
    temp[2] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 2);
    temp[3] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 3);
    high = (uint16_t)((uint16_t)(temp[0] << 8) | temp[1]);
    low = (uint16_t)((uint16_t)(temp[2] << 8) | temp[3]);
    ndata = (uint32_t)((uint32-t)(high << 16)|low);
    return (ndata);
}

以上代码在编绎时会提示移位超出范围的警告:

Warning        left shift count >= width of type [-Wshift-count-overflow]   

当时也没有注意,因为代码里很多从串口接收数据回填的函数都没有出错。直到测试数据大于65535后才发现这个位置的数据返回错误,高16位一直返回的是0;


原因分析:

为了找出问题点,跟踪调试从EEPROM里读取记录条数回填函数,并用串口打印出来发现,数据出错的地方,就是上面左移16位的位置。

测试代码如下:

uint32_t EEread_DataAdd(void)
{
	uint8_t temp[4];
	uint16_t high,low;
	uint32_t ndata;

	temp[0] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr);
	temp[1] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 1);
	temp[2] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 2);
	temp[3] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 3);
	high = (uint16_t)((uint16_t)(temp[0] << 8) | temp[1]);
	low = (uint16_t)((uint16_t)(temp[2] << 8) | temp[3]);
    UART_Send_byte((uint8_t)(high>>8));
    UART_Send_byte((uint8_t)(high&0xff));
    UART_Send_byte((uint8_t)(low>>8));
    UART_Send_byte((uint8_t)(low&0xff));

	ndata = (uint32_t)(high << 16)|low;

	UART_Send_byte((uint8_t)(ndata>>24));
    UART_Send_byte((uint8_t)(ndata>>16));
    UART_Send_byte((uint8_t)(ndata>>8));
    UART_Send_byte((uint8_t)(ndata&0xff));
	return (ndata);
}

通过串口打印信息发现,在移位操作前HIGH和LOW的数据是正常的,而在执行完

ndata = (uint32_t)(high << 16)|low;命令后,打印出的数据高16位一直为0.


解决方案:

因为是移位操作在编绎时出现了警告,所以分析是数据移位导致的问题,所以试着改成如下代码后测试问题解决:

ndata = (uint32_t)(high *65535)+low;
ndata  = ndata +1;//这里要注意,因为是16位数乘,所以最终结果一定要加1,以满足65536的要求。

个人考虑系统是AVR的8位单片机,乘除运算比较耗资源,所以我最终经过测试后选用的是左移8位两次的方法。

uint32_t EEread_DataAdd(void)
{
	uint8_t temp[4];
	uint16_t high,low;
	uint32_t ndata;

	temp[0] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr);
	temp[1] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 1);
	temp[2] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 2);
	temp[3] = FLASH_0_read_eeprom_byte((uint16_t)DataAdd_EEaddr + 3);
	high = (uint16_t)((uint16_t)(temp[0] << 8) | temp[1]);
	low = (uint16_t)((uint16_t)(temp[2] << 8) | temp[3]);
	ndata = (uint32_t)(high << 8);  //左移8位
	ndata =  (ndata<< 8)|low;     //再次左移8位,相当于左移16位,避开直接左移16位出现结果错误的问题
	return (ndata);
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 警告:\ xe2 \ x80 \ x98-werror = \ xe2 \ x80 \ x99参数\ xe2 \ x80 \ x98-werror = non-virtual-dtor \ xe2 \ x80 \ x99不适用于c. ### 回答2: 在C语言中,-werror=non-virtual-dtor不是一个有效的选项。这是因为C语言没有虚拟析构函数这个概念,因此这个选项是多余的。虚拟析构函数只在C++中有用。 警告出现的原因可能是因为在编译时使用了一些C++选项,而源代码中存在一些不兼容的内容。这些选项可能在编译器中默认开启,因此可能会出现警告。 解决这个问题的方法是检查编译选项并相应地更改它们。如果是在使用类似于Makefile的简单编译器命令行工具中编译代码,则需要手动更改命令行选项。 在Makefile中,可以将编译器命令行中的“-Werror=non-virtual-dtor”选项删除,或者简单地将其替换为“-Wno-non-virtual-dtor”选项。 总之,这个警告是因为选项不适用于C语言。如果遇到这种警告,需要检查编译选项并相应地更改它们,以使其适用于C语言。 ### 回答3: 在C语言中,不存在虚析构函数的概念,因此使用“-werror=non-virtual-dtor”参数来强制编译器在编译代码时将没有虚析构函数的类作为警告或错误报告是无效的。 虚析构函数是用于在删除已分配的对象时,确保正确处理多态类的析构函数。在C++中,虚析构函数是很常见的,但在C语言中并不支持虚析构函数。因此,C语言编译器会忽略“-werror=non-virtual-dtor”参数,并将其视为无效参数。 此外,C语言是一种不支持面向对象程序设计的编程语言,因此它不支持类和对象的概念。相反,C语言更注重可移植性和对底层硬件的直接控制。因此,在C语言中使用虚析构函数的需求也就相应减少了。 总结来说,在C语言中不存在虚析构函数的概念,因此在编译代码时使用“-werror=non-virtual-dtor”参数是没有意义的。如果想要使用虚析构函数,应该采用面向对象的编程语言,比如C++。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值