Jump to content

    
Darth Vader

Инициализация объединений в С++

Recommended Posts

В Си можно сделать так:

#include <stdint.h>

// Объявляю тип объединения
typedef union {
  uint32_t  Word;
  uint16_t  HWord[2];
  uint8_t   Byte[4];
} WordUnion_t;

// Объявляю и инициализирую константный массив из 3-х объединений
const WordUnion_t MyVal[3] = {
    {.Byte = {0x12,0x34,0x12,0x34}},    // Это объединение инициализировано, как массив байт
    {.HWord = {0x5678,0x1234}},         // Это объединение инициализировано, как массив полуслов
    {.Word = 0x12345678}                // Это объединение инициализировано, как массив слов
};

С++ такое не поддерживает. Ему нельзя явно задать поле объединения, которое я хочу инициализировать.

Убираем имена полей и пытаемся инициализировать, как обычные структуры в С++:

const WordUnion_t MyVal[3] = {
  {0x12,0x34,0x12,0x34},
  {0x5678,0x1234},
  {0x12345678}
};

Компилятор и на это ругается. Только элемент MyVal[2], по его мнению, инициализирован верно.

Эксперимент показал, что инициализировать объединение в С++ можно только по полю, объявленному первым при описании этого объединения. В моем случае, по .Word. Что бы мы ни писали в инициализаторах, он расценивает это, как значение поля Word.

Собственно, вопрос: а если мне надо/удобно инициализировать моё объединение по другому полю, неужели синтаксис языка этого не позволяет?

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

Share this post


Link to post
Share on other sites

Да, это почти единственная сишная фишка, которой мне не хватает в плюсах.

Конкретно в этом случае можно выкрутиться, написав конструкторы для объединения:

union MySuperPuperUnion
{
  uint32_t  Word;
  uint16_t  HWord[2];
  uint8_t   Byte[4];
  MySuperPuperUnion(uint32_t w) : Word(w){}
  MySuperPuperUnion(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4){
    Byte[0] = b1;
    Byte[1] = b2;
    Byte[2] = b3;
    Byte[3] = b4;
  }
  MySuperPuperUnion(uint16_t w1, uint16_t w2){
    HWord[0] = w1;
    HWord[1] = w2;
  }
};

const MySuperPuperUnion MyVal[3] = {
  MySuperPuperUnion(0x12,0x34, 0x56, 0x78),
  MySuperPuperUnion(0x1234,0x5678),
  MySuperPuperUnion(0x12345678),
};

 

Share this post


Link to post
Share on other sites
3 hours ago, Darth Vader said:

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

может через asm как-то вывернуться (или вставка или отдельный модуль, или-или . . .), если "игра стоит свеч" и времени.

Share this post


Link to post
Share on other sites
3 часа назад, Darth Vader сказал:

Собственно, вопрос: а если мне надо/удобно инициализировать моё объединение по другому полю, неужели синтаксис языка этого не позволяет?

Сделать это поле первым? 

Share this post


Link to post
Share on other sites
7 часов назад, MegaVolt сказал:

Сделать это поле первым?

Не решает проблемы. В разных местах программы, для разных целей, мне удобно задавать значение разных полей объединения. Где-то слова, где-то массива из 4-х байт.

Что-то комитет по стандартизации С++ проворонил этот момент.

Конструкторы объединения - интересная идея.

Share this post


Link to post
Share on other sites
const WordUnion_t MyVal[3] = {
  {Byte: {0x12,0x34,0x12,0x34}},    // Это объединение инициализировано, как массив байт
  {HWord: {0x5678,0x1234}},         // Это объединение инициализировано, как массив полуслов
  {Word: 0x12345678}                // Это объединение инициализировано, как массив слов
};

А так?

Share this post


Link to post
Share on other sites
10 минут назад, adnega сказал:

А так?

Ух ты, круть. Я не знал про такое. Это только для объединений? (Для структур случайно не завезли? :-))

Share this post


Link to post
Share on other sites

Для структур тоже работает. Это gcc, не уверен, что везде так можно.

Так очень удобно задавать

int  rpm_arr_pos[RPM_NUM] = {[0 ... (RPM_NUM - 1)] = 0};

Не только массивы, но и массивы структур/объединений.

Share this post


Link to post
Share on other sites

Ага, понял. Это gcc-шное расширение:

Цитата

warning: ISO C++ does not allow GNU designated initializers [-Wpedantic]

Полез искать информацию про это, обнаружил, что в c++20 designated initializers таки завезут, хотя и с некоторыми ограничениями.

Share this post


Link to post
Share on other sites
8 минут назад, adnega сказал:

Не только массивы, но и массивы структур/объединений.

А структуру из массивов так можно? Я тему такую создавал.

Share this post


Link to post
Share on other sites
20 минут назад, ViKo сказал:

А структуру из массивов так можно? Я тему такую создавал.

Думаю, это все не в духе С++ ;)

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.