Можно ли объявить анонимный экземпляр в объединении на С++?

Работая с низкоуровневым C++ для встраиваемых систем без ПО (STM32), я столкнулся с примером использования объявления "анонимного члена союза" с нетривиальным (структурным) типом. Возможно ли подобное?

Я пробовал следующий вид кода:

struct Specialization_CR1_t
{
        uint32_t a :1 ;
        uint32_t   :31;
};

struct CR1_t
{
    union
    {
        struct
        {
            uint32_t  : 1;
            uint32_t b: 1;
            uint32_t  :30;
        } ;
        // Few tries...
        // Specialization_CR1_t {};
        // Specialization_CR1_t;
        Specialization_CR1_t () ; 
        // Fails with "expected unqualified-id before ')'"
    };
};

int main()
{
    //The goal :
    struct CR1_t CR1;
    CR1.a = 1;
    CR1.b = 0;
}

Цель состоит в том, чтобы избежать CR1.<thing>.a. Очевидно, что есть возможность напрямую объявить Specialization_CR1_t анонимно в union, однако конечная цель состоит в том, чтобы иметь возможность использовать шаблон и tmpl_CR1_t вместо "просто" Specialization_CR1_t.

Я знаю о потенциальных проблемах с памятью из-за материалов, отображаемых здесь. Однако, поскольку это встроенная среда с голым железом, структура памяти полностью известна, биты упакованы хорошо и плотно, а цепочка инструментов исправлена ​​(без проблем с битовыми полями).

Более того, поскольку эта структура будет отображаться непосредственно в памяти, я не могу позволить себе накладные расходы на еще одну переменную. Общий размер моей структуры должен быть 32 бита, и запись в a или b должна изменить только правильный бит.

С наилучшими пожеланиями !


person J Faucher    schedule 28.02.2020    source источник
comment
Анонимная структура не допускается в стандартном C++. Даже без использования Specialization_CR1_t в качестве участника ваш код недействителен. К сожалению, некоторые компиляторы C++ поддерживают это по умолчанию как расширение (возможно, поскольку C делает (?)) - если вы запустите свой компилятор, чтобы выдать больше предупреждений/диагностик (например, -Wall -pedantic для gcc), он, вероятно, скажет вам это. Именование элементов структуры или объединения в любом случае не приводит к дополнительным накладным расходам с точки зрения использования памяти.   -  person Peter    schedule 28.02.2020
comment
На самом деле это не запрещено, как указано в en.cppreference.com/w/cpp/language. /classes : имя может быть опущено, и в этом случае класс будет безымянным (обратите внимание, что безымянный класс не может быть окончательным). Более того, проблема с именованными членами связана не с накладными расходами, а с моей целью.   -  person J Faucher    schedule 28.02.2020
comment
Вы упустили мою мысль. Имя Foo в struct Foo { <members>}; внутри класса/объединения можно опустить. Имя Instance в struct {<members>} Instance не может.   -  person Peter    schedule 29.02.2020
comment
Ох, хорошо. Я действительно читал об этом. Однако, начиная с C11 (в котором это представлено), кажется, что большинство компиляторов C++ принимают его, даже если он не является стандартным. Я использовал его полностью без проблем в течение нескольких лет без проблем. Дело в том, чтобы использовать это внутри союза. (Это может работать внутри класса, но это было бы удивительно). Однако в этом контексте это действительно полезно...   -  person J Faucher    schedule 29.02.2020
comment
Да, хорошо. В дополнение к указанию вашего набора микросхем вы также можете указать свой компилятор. Если вы хотите использовать нестандартные языковые функции, вы будете в сфере использования функций, специфичных для вашего компилятора. Для чипсетов на базе ARM доступно более одного компилятора.   -  person Peter    schedule 29.02.2020
comment
никогда не следует использовать объединения и структуры в доменах компиляции, а также использовать такие объединения, которые не являются их целью, тот же код можно сгенерировать с помощью чего-то более чистого и надежного.   -  person old_timer    schedule 17.03.2020


Ответы (1)


ISO C11 позволяет использовать анонимные структуры внутри других структур/объединений. Это поддерживается как расширение некоторыми компиляторами C++, в том числе совместимыми с GNU (g++, clang++) и MSVC++. В руководстве GCC есть несколько примеров.

Это AFAIK не разрешено в ISO C++. Если вы используете компилятор, который не реализует это расширение, см. среднюю часть этого ответа.


Я почти уверен, что анонимное объединение является здесь отвлекающим маневром, и у вас будет точно такая же проблема, пытаясь объявить b как 32-битный объект с 31 битом заполнения и 1 битом значения, используя эту анонимную структуру в любом другой контекст.

Если бы это было законно внутри анонимного союза, это было бы законно везде. (Но вместо этого это не так, и нигде в ISO C это не разрешено. Как указывает @Peter в комментариях, имя Instance в struct {<members>} Instance нельзя опустить. И если вы сделаете его struct foo {<members>};, вы просто объявите тип, а не пример.)

Возможно, вам просто придется написать класс с перегрузками operator= и operator bool, что вы можете сделать, потому что это C++.

(Подумайте о том, чтобы переименовать вопрос в том, что вы на самом деле пытаетесь сделать: написать анонимную структуру с членом битового поля.)

Или, если вам нужна помощь с классом-оболочкой, сделайте шаг назад от проблемы X-Y, где подход с анонимной структурой, по-видимому, зашел в тупик (если только для него нет какой-либо поддержки, специфичной для компилятора), и задайте новый вопрос о написании класса. удобная оболочка, которая представляет один бит в слове как целочисленный тип. С заголовками поставщиков, расширениями компилятора или простыми перегрузками операторов или операторов C++.

Хотя, учитывая то, как вы используете союз, вы можете сделать это, чтобы получить то, что хотите, по крайней мере, без шаблонов, верно?

struct CR1bits
{
    uint32_t a: 1;
    uint32_t b: 1;
    uint32_t  :30;
};

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


Анонимные структуры являются стандартом C11 или расширением C++:

GNU C++ и MSVC поддерживают анонимные структуры. Это компилируется и работает:

union Obj {
   struct {       // extension: anonymous struct
      int x;
      int y;
      int z;
   };
   int elems[3];
};

a->x или a->elems[0] оба обращаются к одному и тому же объекту (при условии стандартной структуры структуры без заполнения).

И судя по всему это стандарт ISO C11.

person Peter Cordes    schedule 01.03.2020
comment
Так что это хорошо аргументированное нет. Хотя кажется вполне законным, что это невозможно. В конце концов я решил подняться на один уровень вверх (добавить a и b в Specialization_CR1_t ) и поиграться с ifdefs. Это может работать только потому, что мои исходные файлы генерируются с помощью сценария, и я довольно ограничителен в своих определениях. Определенно не лучший способ работать в более обычном случае использования. Спасибо за ваши конструктивные замечания. - person J Faucher; 05.03.2020
comment
@JFaucher: Оказывается, некоторые компиляторы поддерживают анонимные структуры. Недавно я хотел превратить структуру в объединение с массивом, чтобы я мог индексировать элементы, и, к моему удивлению, он скомпилировался. Оказывается, GCC реализует это как расширение C++ и является стандартом в ISO C11. - person Peter Cordes; 25.03.2020
comment
Просто чтобы добавить некоторую информацию, по крайней мере, GCC реализует ее на стандартном C++ (например, вам не нужно использовать версию gnu++XX, чтобы она работала. Я использовал ее довольно широко, видя какие-либо проблемы ( с GCC в c++11 и выше) Если вы хотите проверить проект, над которым я работаю (ранняя стадия разработки, на самом деле работает сейчас, но я видел, что соответствующие коммиты не были отправлены), вы можете проверить репозиторий SooL github - person J Faucher; 27.03.2020