Компиляция с разными версиями gcc в Ubuntu дает разные результаты - PullRequest
0 голосов
/ 14 февраля 2019

Итак, у меня есть настройка проекта, похожая на эту:

  • myfile.cpp, которая включает в себя:
    • fsl_clock.h

Где myfile - это файл C ++, а fsl_clock.h - это чистый заголовочный файл C из NXP, где можно увидеть его версию здесь

Мой файл выглядит так:

#include "fsl_clock.h"

Теперь у меня есть больше материала в моем файле, но я опустошил его, пока не остался только с этим.

Вот компиляции, которые я пробовал вместе с результатами:

  • С кросс-компилятором arm arm-none-eabi-g++ это прекрасно скомпилируется.
  • С хостом (x86Linux) g ++ --version 7.3.0-16ubuntu3 работает нормально
  • С хостом (x86Linux) g ++ --version 7.3.0-27ubuntu1~18.04 выдает множество странных ошибок.

Я получаю следующие ошибки:

device/MIMX8MQ6_cm4.h8856:51: error 'reinterpret_cast<CMM_Type*>(808976384)' is not a constant expression

Где строка кода - чистый C и выглядит так:

kCLOCK_RootM4 = (uint32_t)(&(CCM)->ROOT[1].TARGET_ROOT)

Где CCM определяется как:

#define CCM_BASE (0x30380000u)
#define CCM ((CCM_Type*)CCM_BASE)

Таким образом, похоже, что более новый g ++ 7.3.0-27ubuntu1~18.04 (возможно, правильно) выполняет вещи на языке c ++ (например, reinterpret_cast) во включенном коде заголовка в стиле C.Старый компилятор 7.3.0-16ubuntu3 ведет себя не так - и компиляция идет нормально.

Кто-нибудь может сказать, в чем разница между двумя компиляторами и почему один работает, а другой нет?Оба компилятора gnu g ++ имеют одинаковую версию g ++ 7.3.0.Но я не совсем понимаю суффикс 16ubuntu3 против 27ubuntu1~18.04 и почему это может изменить поведение ...

Примечание Теперь я знаю, что для моей сборки хоста я нена самом деле не хочу включать в сборку хоста специфичный для платы код, но это другой вопрос.Сейчас меня больше интересует понимание того, почему между двумя компиляторами есть разница.

Обновление

Для сборки хоста строка компилятора выглядит следующим образом:

g++ -w -Isource/drivers -Isource/board -Isource/device -m32 -g -std=c++11 -c source/myfile.cpp -o out.o 

CMM_Type (необходимо вручную скопировать его, поскольку оригинал похоронен на веб-сайте NXP) выглядит (обратите внимание, что его сокращенно, потому что копировать слишком много - но его структуры из uint32_t):

typedef struct {
   volatile uint32_t GPR0;
   volatile uint32_t GPR0_SET;
   struct {
      :
   } PLL_CTRL[39];
      :
   struct {
      volatile uint32_t TARGET_ROOT;
      volatile uint32_t TARGET_ROOT_SET;
      volatile uint32_t TARGET_ROOT_CLR;
         :
   } ROOT[142];
} CCM_Type;

Минимальный пример - онлайн GDB Я сделал минимальный пример - он не компилируется с онлайн GDB, но он выдает ошибки, которые я объяснил на моем компиляторе.Ссылка здесь

Минимальная - Wandbox Точно такой же код, как и в примере с GDB онлайн, но на самом деле отображается та же ошибка, что и я: здесь

Минимальный пример кода

#include <stdint.h>

typedef struct {
    struct {
        volatile uint32_t TARGET_ROOT;
    } ROOT[4];
} CCM_Type;

#define CCM_BASE (0x30380000u)
#define CCM ((CCM_Type *)CCM_BASE)

typedef enum _clock_root_control
{
    kCLOCK_RootM4 = (uint32_t)(&(CCM)->ROOT[1].TARGET_ROOT)
} clock_root_control_t;

int main()
{
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019
typedef enum _clock_root_control
{
    kCLOCK_RootM4 = (uint32_t)(&(CCM)->ROOT[1].TARGET_ROOT)
} clock_root_control_t;

Этот код недопустим в C или C ++.

В C ++ перечислитель должен быть константным выражением.Константное выражение не может включать reinterpret_cast.Приведение в C-стиле от указателя к целому числу эквивалентно reinterpret_cast.

В C перечислитель должен быть целочисленным константным выражением.Целочисленное константное выражение не может включать в себя операнды-указатели.

Способ исправить это - заменить выражение эквивалентным константным выражением, например,

CCM_BASE + offsetof(CCM_Type, ROOT[1].TARGET_ROOT)

Живой пример

0 голосов
/ 14 февраля 2019

reinterpret_cast и приведения в стиле C не могут быть оценены компилятором во время компиляции, и это особенно верно, когда они создают указатели, которые вы затем разыменовываете.enum константы должны получать значения во время компиляции.В этой ситуации я бы использовал целочисленные значения CCM_BASE и offsetof.

#include <cstddef>

typedef enum _clock_root_control
{
    kCLOCK_RootM4 = CCM_BASE + offsetof(CCM_Type, ROOT[1].TARGET_ROOT)
} clock_root_control_t;

Вы знаете, что все ваши разыменования указателей в исходном примере бессмысленны, потому что вы просто используете& оператор для получения адреса.Но это не имеет значения.Эта разыменование должно быть действительным и исполняемым, чтобы компилятор мог оценить его во время компиляции.Адрес, с которым вы работаете, не имеет значения для вашего компилятора.Кто знает, что там, или даже если это относится к отображенной странице?И, конечно же, компиляция программы на C ++ в любом случае не должна приводить к случайному взлому в памяти компилятора.

И это верно для C или C ++.Поскольку ваш код является технически неопределенным поведением, он может работать случайным образом для некоторых компиляторов.И большинство компиляторов, предназначенных для платформ, на которых вы хотите использовать код такого типа, будут делать то, что вы ожидаете, когда код выполняется во время выполнения.

Но для оценки времени компиляции offsetofмакрос в <csstddef> обрабатывает все эти детали для вас и определяет поведение.Это то, что вы хотите и нужно здесь.

...