Можно ли объявить анонимный экземпляр в объединении в C ++? - PullRequest
1 голос
/ 28 февраля 2020

При работе с низкоуровневым 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 должна изменить только правильный бит.

С уважением!

1 Ответ

1 голос
/ 01 марта 2020

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

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


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

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

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

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

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

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

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

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


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

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

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

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

И, очевидно, это стандарт ISO C11.

...