Более новая версия GCC выдает ошибку reinterpret_cast - PullRequest
0 голосов
/ 06 января 2019

Я занимаюсь разработкой встроенного проекта (на STM32). В настоящее время я использую GCC 4.9.2, но я бы хотел перейти на более новую версию моего набора инструментов. К сожалению, мой код, который успешно компилируется в gcc 4.9.2, выдает ошибки reinpreted_cast в версии 6.2.0 или 7.2.0, и я понятия не имею, почему. Похоже, что более новый gcc видит некоторые проблемы при приведении int к указателю и обратно к int - что, я думаю, должно быть вполне нормальной операцией.

Сгенерировано сообщение об ошибке:

1>STM32L4\CMSIS\stm32l4a6xx.h(1567,30): error : 'reinterpret_cast<ADC_TypeDef*>(1342439424)' is not a constant expression
1>          #define ADC1                ((ADC_TypeDef *) ADC1_BASE)
1>                                       ^
1>         Sources\CAdc.cpp(31,35): note:  in expansion of macro 'ADC1'
1>             case reinterpret_cast<uint32_t>ADC1: u32DMAChannel = LL_DMA_CHANNEL_1; break;

Вот часть моего кода, к которой относится ошибка:

switch ((uint32_t)adc)
{
case (uint32_t)ADC1: u32DMAChannel = LL_DMA_CHANNEL_1; break;
case (uint32_t)ADC2: u32DMAChannel = LL_DMA_CHANNEL_2; break;
case (uint32_t)ADC3: u32DMAChannel = LL_DMA_CHANNEL_3; break;
}

И adc объявление:

private:
   ADC_TypeDef *adc;

Вот все определения макросов:

#define PERIPH_BASE           (0x40000000UL) /*!< Peripheral base address */
#define AHB2PERIPH_BASE       (PERIPH_BASE + 0x08000000UL)
#define ADC1_BASE             (AHB2PERIPH_BASE + 0x08040000UL)
#define ADC1                  ((ADC_TypeDef *) ADC1_BASE)

Так что для компилятора мой приведенный ниже тип выглядит следующим образом:

(uint32_t)((ADC_TypeDef *) (((0x40000000UL)+ 0x08000000UL)+ 0x08040000UL))

Простое приведение unsigned long к некоторому указателю структуры и обратно к unsigned long. Что с этим не так? Что я должен сделать, чтобы избавиться от этой ошибки? Любое редактирование макросов для меня невозможно, потому что это библиотеки BSP.

Ответы [ 2 ]

0 голосов
/ 06 января 2019

Это не переосмысление, которое дает сбой, а переосмысленное значение не рассматривается как константа, поэтому его нельзя использовать в качестве метки регистра.

Метки регистра должны быть константным выражением , а константное выражение - это любое выражение, которое может быть оценено во время компиляции. В C ++ оценка выражения reinterpret_cast не является константным выражением .

Здесь меняется поведение компилятора, так как компилятор переводит приведенный ранее стиль C в стиле грубой силы в более строгий C ++ reinterpret_cast. Тестирование на https://www.onlinegdb.com/ показывает, что это происходит, когда используется компиляция C ++ 17, но не C ++ 14, поэтому простое решение «без изменения кода» состоит в том, чтобы установить компиляцию на более ранний стандарт - возможно, разумный в любом случае используйте устаревший код, чтобы избежать каких-либо других неожиданностей или ошибок.

Однако, похоже, что заголовок stm32l4a6xx.h уже предоставляет два представления базового адреса АЦП: одно целое число (ADCx_BASE), а другое указатель (ADCx). Как правило, лучше вообще избегать приведений и использовать соответствующее представление цели. В этом случае:

switch ((uint32_t)adc)
{
    case ADC1_BASE: u32DMAChannel = LL_DMA_CHANNEL_1; break;
    case ADC2_BASE: u32DMAChannel = LL_DMA_CHANNEL_2; break;
    case ADC3_BASE: u32DMAChannel = LL_DMA_CHANNEL_3; break;
}
0 голосов
/ 06 января 2019

Вы можете изменить код, чтобы избежать приведения в case с switch:

switch ((uint32_t)adc)
{
    case ADC1_BASE: u32DMAChannel = LL_DMA_CHANNEL_1; break;
    case ADC2_BASE: u32DMAChannel = LL_DMA_CHANNEL_2; break;
    case ADC3_BASE: u32DMAChannel = LL_DMA_CHANNEL_3; break;
}
...