c - 左移计数> = C宏中的类型宽度
问题描述
我编写了一个 C 宏来设置/取消设置 uint32 变量中的位。以下是宏的定义:
extern uint32_t error_field, error_field2;
#define SET_ERROR_BIT(x) do{\
if(x < 0 || x >63){\
break;\
}\
if(((uint32_t)x)<32U){\
(error_field |= ((uint32_t)1U << ((uint32_t)x)));\
break;\
} else if(((uint32_t)x)<64U){\
(error_field2 |= ((uint32_t)1U<<(((uint32_t)x)-32U)));\
}\
}while(0)
#define RESET_ERROR_BIT(x) do{\
if(((uint32_t)x)<32U){\
(error_field &= ~((uint32_t)1U<<((uint32_t)x)));\
break;\
} else if(((uint32_t)x) < 64U){\
(error_field2 &= ~((uint32_t)1U<<(((uint32_t)x)-32U)));\
}\
} while(0)
我正在传递一个枚举字段,如下所示:
enum error_bits {
error_chamber01_data = 0,
error_port21_data,
error_port22_data,
error_port23_data,
error_port24_data,
/*this goes on until 47*/
};
产生此警告:
左移计数 >= 类型的宽度 [-Wshift-count-overflow]
我这样称呼宏:
USART2->CR1 |= USART_CR1_RXNEIE;
SET_ERROR_BIT(error_usart2);
/*error_usart2 is 47 in the enum*/
return -1;
我在每个宏中都会收到此警告,即使是左移计数 < 31 的宏。
如果我在没有宏的情况下使用宏的定义,则不会产生警告。行为与 64 位变量相同。我正在使用 AC6 STM32 MCU GCC 编译器对 STM32F7 进行编程。我不明白为什么会这样。谁能帮我?
解决方案
如 M Oehm 所述,可能是编译器无法正确诊断的问题。一种解决方法可能是,而不是使用减号运算,而是使用余数运算:
#define _SET_BIT(x, bit) (x) |= 1U<<((bit) % 32U)
#define SET_BIT(x, bit) _SET_BIT(x, (uint32_t)(bit))
#define _SET_ERROR_BIT(x) do{\
if((x)<32U){\
SET_BIT(error_field, x);\
} else if((x)<64U){\
SET_BIT(error_field2, x);\
}\
}while(0)
#define SET_ERROR_BIT(x) _SET_ERROR_BIT((uint32_t)(x))
这样编译器终于足够聪明,知道 的值x
永远不会超过 32。
对“_”宏的调用用于强制x
始终为 uint32_t,无条件地调用宏,避免使用负值的调用的 UB x
。
推荐阅读
- ios - 在 iPhone 4s 中播放时,视频最后会冻结
- maven - maven:禁用surefire控制台错误(或修复控制台错误编码)
- angular - 如何使用 Angular 6 拦截器更改 http req url
- angular-material - 如何导入 Angular 材质 Css
- git - 如何硬恢复并再次提交到服务器
- java - JAVA CSV 写空格不带引号
- unit-testing - 测试使用全局事件总线的 Vue 单文件组件
- java - glassfish 4.1.2 web 容器未启动
- pandas - 我怎样才能调整这个数据框索引?
- javascript - Chrome 扩展脚本在注入后不会执行