Почему Clang запрещает использование квалификаторов в анонимных битовых полях?

У меня есть следующий тестовый код:

struct{
      const int   : 1;
      const int b : 1;
} bit = {0};

int main(void) {
    return bit.b;
}

Большинство компиляторов, включая последнюю версию GCC, компилируют его нормально, но Clang, начиная с версии 8, жалуется на «const» в анонимном битовом поле:

[source]:2:22: error: anonymous bit-field cannot have qualifiers
     const int   : 1;

Та же ошибка происходит с квалификатором «летучий». В чем причина того, что Clang так строг в отношении квалификаторов, и есть ли способ заставить замолчать эту ошибку?

Справочная информация: у меня есть автоматически сгенерированные файлы заголовков «Определение аппаратного регистра», которые представляют неиспользуемые биты и анонимные битовые поля, а квалификаторы, такие как «летучие константы» или «летучие», систематически используются для всех битов в регистре. Просматривать такие файлы и вручную удалять квалификаторы в анонимных полях — не вариант.

приемлемо ли использование сценария для выполнения задачи удаления?

Oersted 12.06.2024 14:13

Также знайте, что битовые поля, вероятно, НЕ делают то, что вы думаете. Компилятор может реализовать битовые поля любым способом (в пределах указанных вами типов). В лучшем случае он генерирует целочисленную переменную, которая как 1-битная арифметика, а не переменная, которая точно занимает один бит в вашей переменной. Таким образом, наличие безымянного битового поля не будет служить какой-либо (логической) цели.

Pepijn Kramer 12.06.2024 14:15

Вероятно, вам следует использовать std::bitset<> (без контроля над базовым типом) или написать небольшой класс, который выполняет за вас побитовые операции с базовым типом.

Pepijn Kramer 12.06.2024 14:17

@Oersted не должен, говоря стандартным языком, означает, что это запрещено или соответствующий компилятор должен отклонить этот код. Стандарт C++ соответствует ISO OBP в отношении терминологии (согласно intro.defs#2.1 ), а OBP говорит «не должен» — указывает на требования, которые необходимо строго соблюдать для соответствия документу и от которых не допускаются никакие отклонения. "

Yksisarvinen 12.06.2024 14:31

@Yksisarvinen Спасибо. Таким образом, cl и gcc неверны?

Oersted 12.06.2024 14:45

@Oersted На данный момент приемлемым решением является простой переход на GCC, однако я пытаюсь предвидеть возможность исправления программного обеспечения после обновления GCC. И да, изменение с помощью сценария было бы моим запасным планом.

Dmitry Grigoryev 12.06.2024 14:45

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

Dmitry Grigoryev 12.06.2024 14:53

@DmitryGrigoriev Тогда вы полагаетесь на то, что этот конкретный компилятор сделает правильные действия (вы проверили, что сборка делает это?). Я все равно посоветовал бы вам создать небольшой шаблон класса, который выполняет за вас битовые операции (возможно, даже добавить некоторые элементы constexpr, чтобы перемещать вещи во время компиляции, что хорошо для встраивания).

Pepijn Kramer 12.06.2024 15:05

Вы вдохновили меня попробовать это: godbolt.org/z/8WecqTaoM

Pepijn Kramer 12.06.2024 16:32

@PepijnKramer Для сборок ПО, ориентированных на реальное оборудование, я использую компилятор, который рекомендует производитель ASIC, поэтому проверка сборки будет его обязанностью. Именно поэтому я не хочу прикасаться к этим заголовкам, предоставленным производителем: я не хочу нести ответственность за тестирование и обслуживание. Для тестовых сборок (например, модульных тестов с помощью Google Test) меня фактически не волнует, как компилятор распределяет битовые поля.

Dmitry Grigoryev 13.06.2024 10:43

@DmitryGrigoriev В этом случае справедливый подход (компилятор конкретного поставщика + оборудование конкретного поставщика). Я просто больше привык писать переносимый код, а «реализация, определенная» в стандарте C++, является немного сложной областью.

Pepijn Kramer 13.06.2024 13:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
12
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Потому что Clang реализует CWG2229 (из-за чего было неправильно использовать тип с указанием cv для безымянного битового поля), а GCC - нет.

В настоящее время у Clang нет возможности игнорировать эту ошибку. Это недействительно для C++, вам придется автоматически генерировать структуры (либо без квалифицированных типов, либо с именем типа _padding1).

@463035818_is_not_an_ai Добавление имени делает его больше не безымянным битовым полем. Я думаю, что Microsoft делает это для всех своих битовых полей.

Artyer 12.06.2024 15:14

ох. нужно больше кофе

463035818_is_not_an_ai 12.06.2024 15:15

Я думаю, что причина, по которой этого не было сделано, в первую очередь — автозаполнение. В современных ASIC все регистры имеют одинаковый размер (например, 32-битный), даже если на самом деле используется всего пара бит. Вы же не хотите, чтобы пользователи набирали Uart->CtlrReg. и видели всплывающее окно с бесполезными _paddingX именами.

Dmitry Grigoryev 13.06.2024 10:52

Другие вопросы по теме

Похожие вопросы

Std::partition_copy: что происходит, когда диапазон вывода d_first_true перекрывается с диапазоном ввода?
Как мне обойти то, что кажется целочисленным переполнением, несмотря на то, что тип достаточно большой
Когда необходимо устранить неоднозначность между объявлениями и выражениями?
Захват битовых полей по ссылке в лямбда-выражении
Инициализировать unordered_set как статическую переменную-член вместо инициализации в конструкторе в C++
OpenCL – Как предотвратить появление ошибок сборки при переходе к стандартной ошибке?
Является ли вставка в вектор при одновременном доступе к вектору неопределенным поведением?
Почему указатели на элементы данных можно вызывать в C++?
Ошибка компиляции при использовании функций шаблона C++, которые принимают в качестве аргументов другие функции, которые принимают ссылки на указатели
Специализация шаблона вне встроенного пространства имен функции, определенной внутри встроенного пространства имен