C++ stm32 hal库警告,带C++;十四及;在上面
我也在STM32社区论坛上发布了同样的消息,但没有收到回复 我正在启用C++14的项目中使用stm32 HAL库。它向我发出了以下我无法摆脱的警告 ../platform/stm32/l4/STM32L4xx\u HAL\u Driver/Inc/STM32L4xx\u HAL\u rcc.h:735:57: 警告:转换为void将无法访问“volatile”类型的对象 uint32_t{aka volatile long unsigned int}'未使用(tmpreg)\ 当调用_GPIOX_CLK_ENABLE()或_HAL_RCC_GPIOX_CLK_ENABLE时,就会发生这种情况 有没有人能够摆脱上述警告,保持HAL源代码完整 或者任何可能的想法 当前警告级别为-Wall 我在l4和f4系列代码中都遇到过上述问题 示例代码:C++ stm32 hal库警告,带C++;十四及;在上面,c++,embedded,c++14,stm32,C++,Embedded,C++14,Stm32,我也在STM32社区论坛上发布了同样的消息,但没有收到回复 我正在启用C++14的项目中使用stm32 HAL库。它向我发出了以下我无法摆脱的警告 ../platform/stm32/l4/STM32L4xx\u HAL\u Driver/Inc/STM32L4xx\u HAL\u rcc.h:735:57: 警告:转换为void将无法访问“volatile”类型的对象 uint32_t{aka volatile long unsigned int}'未使用(tmpreg)\ 当调用_GPIOX
int main(void)
{
HAL_Init();
__GPIOB_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = GPIO_PIN_7;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
for (;;)
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
HAL_Delay(500);
}
}
罪魁祸首是\uu GPIOB\u CLK\u ENABLE()
,它扩展到以下内容(在ST驱动程序中)
我最初的问题是为了找到一个解决方案,让底层的ST驱动程序完好无损。
一种可能的解决方案是使用直接寄存器访问,而无需通过库提供的方便宏
提前谢谢。问题是
-std=c++14
将volatile
表达式的语义转换为(void)
,并引入一个明显的*无条件警告,ST的编码员试图“三重确保”寄存器读取会发生
UNUSED()
宏的定义为
#define UNUSED(x) ((void)(x))
而\uu IO
定义为
#define __IO volatile
然后,\uuu HAL\u RCC\u GPIOB\u CLK\u ENABLE()
的扩展将是
do {
volatile uint32_t tmpreg;
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
/* Delay after an RCC peripheral clock enabling */
tmpreg = RCC->AHB2ENR & RCC_AHB2ENR_GPIOBEN;
((void)(tmpreg));
} while(0)
各种STM32勘误表建议寄存器的延迟和读回
为了管理外设读/写寄存器,应考虑RCC外设时钟启用和有效外设启用之间的延迟
[……]
紧接着从相应的寄存器插入一个伪读操作
启用外围时钟
当然,由于所有外围寄存器都声明为易失性,因此仅包含所述寄存器的简单表达式将通过相同的外围总线强制回读必要的等待状态,因此这就足够了:
do {
RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;
/* Delay after an RCC peripheral clock enabling */
RCC->AHB2ENR;
} while(0)
对于一些有缺陷的编译器来说,剩下的可能是一个过度工程化的解决方案,但我还没有看到一个如此破碎的解决方案,以至于带有易失性类型的表达式会被优化掉
然而,有一种边缘情况,一个可变变量被转换为(void)
,在C++14中语义显然发生了变化
让我们举一个简单的例子
void x() {
volatile int t;
t=1;
((void)(t));
}
我会把它编译成
x():
sub sp, sp, #8
movs r3, #1
str r3, [sp, #4]
ldr r3, [sp, #4]
add sp, sp, #8
bx lr
而且是
。。。以及警告:
<source>: In function 'void x()':
<source>:5:13: warning: conversion to void will not access object of type 'volatile int'
((void)(t));
~^~
:在函数“void x()”中:
:5:13:警告:转换为void将无法访问“volatile int”类型的对象
((无效)(t));
~^~
还要注意第二种情况下缺少的ldr
指令。在使用C++14进行写入后,不会访问该变量
我最初的问题是为了找到一个解决方案,让底层的ST驱动程序完好无损。一种可能的解决方案是使用直接寄存器访问,而无需通过库提供的方便宏
我建议继续,避免使用库,IMHO HAL最好被视为示例或实现建议的集合
*我找不到禁用它的方法。这并不意味着没有。您可以将代码提交到自己的存储库中,以解决这个问题,并且仍然可以使用c++14编译代码
/* Workaround for the broken UNUSED macro */
#include "stm32f3xx_hal_def.h"
#undef UNUSED
#define UNUSED(x) ((void)((uint32_t)(x)))
这需要在包含任何HAL头之前添加。对我来说,在模块启用宏之后(即#define hal_WWDG_module_ENABLED
行),但在包含实际的hal头之前,将其放入stm32f3xx_hal_conf.h
文件很方便。
我将所有源代码更新为#包括“stm32f3xx_hal_conf.h”
,而不是单个hal头
这是因为基于@berendi的出色研究,警告来自于
volatile
名称。通过首先将值转换为非易失性的内容,可以避开C++14标准中的新子句 正如@oliv在回答@berendi的回答时提到的,根本原因似乎是GCC中的一个bug,它已在较新版本中修复。当我升级到“9-2019-q4-major版本”工具链(GCC 9.2)时,警告就消失了
此外,对于STM32G0系列,ST将未使用的定义更改为:
#define UNUSED(X) (void)X /* To avoid gcc/g++ warnings */
这使得编译器早期版本的警告消失。我做了一些研究,出现此警告的原因是
未使用的宏(作为上述宏的一部分)对void
进行了不稳定的引用。它与C++14或-Wall无关,但所有g++版本都给出相同的诊断。可以在链接副本中找到原因。解决方案是不使用volatile引用,这在编写与硬件相关的代码时是一种可疑的做法——而是使用volatile指针。也许您使用引用是偶然的?警告不是在C++11中发出的。我可以使用C++11成功地编译相同的代码,而不会使用-Wall
得到任何警告。它肯定不是所有的g++
编译器版本。这就是这个问题背后的原因。它绝对不是重复的。我敦促您下载STM32 CubeMX HAL源代码,并在C++11和C++14中编译它。这个警告在C++14中变得很明显,但在C++11中却从未出现过。我可以通过简单地将任何易失性引用转换为void,将其复制到C++03。所以这与编译器版本无关。在C++14中,调用者代码中一定有一些行为不同的东西。请使用包含发出警告的呼叫方代码的编辑您的问题。我将重新打开
/* Workaround for the broken UNUSED macro */
#include "stm32f3xx_hal_def.h"
#undef UNUSED
#define UNUSED(x) ((void)((uint32_t)(x)))
#define UNUSED(X) (void)X /* To avoid gcc/g++ warnings */