Как использовать c union, вложенный в структуру без имени

Я работаю над так называемым проектом с открытым исходным кодом Hotspot, и, глядя на реализацию, я обнаружил неприятное вложенное объединение в структуре, которое выглядит так:

typedef struct RC_model_t_st
{
    union
    {
        struct block_model_t_st *block;
        struct grid_model_t_st *grid;
    };
    /* block model or grid model    */
    int type;
    thermal_config_t *config;
}RC_model_t;

Насколько мне известно в C / C ++, такое объединение недоступно. Так как же кто-то может использовать объявленный таким образом союз и с какой целью?

Спасибо!


person zwx    schedule 29.11.2012    source источник
comment
Связано: http://stackoverflow.com/questions/1972003/how-to-use-anonymous-structs-unions-in-c   -  person zch    schedule 29.11.2012


Ответы (6)


Это анонимное объединение. В C ++, согласно [class.union], параграф 5:

В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области, в которой объявлено анонимное объединение.

Это означает, что вы можете получить доступ к его участникам, как если бы они были членами RC_model_t_st.

person Angew is no longer proud of SO    schedule 29.11.2012
comment
В порядке. Тогда, если я могу получить к ним доступ как к членам структуры, я не понимаю, зачем кому-то объединять их в анонимный союз? - person zwx; 29.11.2012
comment
@zwx Потому что это все еще союз - они занимают одно и то же место в хранилище. - person Angew is no longer proud of SO; 29.11.2012
comment
С каждой переменной вы выделяете некоторое пространство памяти в n байтов. Теперь тип переменных определяет только, сколько места и как интерпретировать содержимое этого пространства. При объединении переменная использует пространство самого большого типа, интерпретация зависит от члена, к которому вы обращаетесь - person Atmocreations; 29.11.2012

Не будучи уверенным и не пробуя:

Сам союз недоступен, но его члены доступны.

Следовательно, вы должны иметь возможность ссылаться на obj.block и obj.grid

person Atmocreations    schedule 29.11.2012
comment
Вы имеете в виду, что obj - это RC_model_t? - person zwx; 29.11.2012

Чтобы уточнить ответ, предоставленный Энгью, цитирующим стандарт, касающийся анонимных объединений и структур, я подумал предоставить образец исходного кода C с выводом, сгенерированным этим образцом, показывающим, как значения распределяются в struct и union, состоящих из struct и union компоненты.

Стандарт, цитируемый Энгью:

В целях поиска имени после определения анонимного объединения члены анонимного объединения считаются определенными в области действия, в которой объявлено анонимное объединение.

Исходный код struct, состоящего из именованных и анонимных структур и объединений, выглядит следующим образом. Здесь используется Visual Studio 2005, а #pragma (pack, 1) используется для выравнивания всего на char границе, чтобы не было дыр в памяти. Существует также простой макрос препроцессора C, который делает вывод более разборчивым и упрощает кодирование.

typedef unsigned char UCHAR;

// use of Microsoft Visual Studio pragma to force char alignment for the struct.
#pragma pack(push, 1)
const struct {
    union {
        const UCHAR myArray[];  // this array shares memory with struct following
        struct {
            const UCHAR iOne;
            const UCHAR iTwo;
            const UCHAR iThree;
        };  // anonymous struct accessed by specifying Things.
    };      // anonymous union accessed by specifying Things.
//  const UCHAR myArray[];   // will cause error - "error C2020: 'myArray' : 'struct' member redefinition"
    union {
        const UCHAR myArray[];  // this array shares memory with struct following
        struct {
            const UCHAR iOne;
            const UCHAR iTwo;
            const UCHAR iThree;
        } s;    // named struct accessed by specifying Things.u.s
    } u;        // named union accessed by specifying Things.u
} Things = {1, 2, 4, 8, 9, 10, 22, 23, 24, 25};
#pragma pack(pop)

// a little helper macro to make the output easier to code.
#define PRINTF_VAL(x) printf ("%s %d \n", #x, x)

int itSelf (UCHAR iMask)
{
    int iMatch = -1;

    int jj = 0;
    jj = Things.myArray[0]; PRINTF_VAL(Things.myArray[0]);
    jj = Things.myArray[1]; PRINTF_VAL(Things.myArray[1]);
    jj = Things.myArray[2]; PRINTF_VAL(Things.myArray[2]);
    jj = Things.myArray[3]; PRINTF_VAL(Things.myArray[3]);
    jj = Things.myArray[4]; PRINTF_VAL(Things.myArray[4]);
    jj = Things.iOne; PRINTF_VAL(Things.iOne);
    jj = Things.iTwo; PRINTF_VAL(Things.iTwo);
    jj = Things.iThree; PRINTF_VAL(Things.iThree);

    jj = Things.u.myArray[0]; PRINTF_VAL(Things.u.myArray[0]);
    jj = Things.u.myArray[1]; PRINTF_VAL(Things.u.myArray[1]);
    jj = Things.u.myArray[2]; PRINTF_VAL(Things.u.myArray[2]);
    jj = Things.u.myArray[3]; PRINTF_VAL(Things.u.myArray[3]);
    jj = Things.u.myArray[4]; PRINTF_VAL(Things.u.myArray[4]);
    jj = Things.u.s.iOne; PRINTF_VAL(Things.u.s.iOne);
    jj = Things.u.s.iTwo; PRINTF_VAL(Things.u.s.iTwo);
    jj = Things.u.s.iThree; PRINTF_VAL(Things.u.s.iThree);

    return iMatch + 1;
}

Результат, сгенерированный этой функцией, выглядит так:

Things.myArray[0] 1
Things.myArray[1] 2
Things.myArray[2] 4
Things.myArray[3] 8
Things.myArray[4] 9
Things.iOne 1
Things.iTwo 2
Things.iThree 4
Things.u.myArray[0] 8
Things.u.myArray[1] 9
Things.u.myArray[2] 10
Things.u.myArray[3] 22
Things.u.myArray[4] 23
Things.u.s.iOne 8
Things.u.s.iTwo 9
Things.u.s.iThree 10

Выходные данные показывают перекрытие между различными компонентами главного struct, Things, вызванное использованием объединений. Вы также можете увидеть, как упоминаются компоненты анонимных struct и union по сравнению с компонентами именованных struct и union.

Также ради забавы я попытался добавить определение массива const UCHAR myArray[]; после анонимного union, содержащего const UCHAR myArray[];, чтобы посмотреть, что произойдет. Компилятор пожаловался на ошибку error C2020: 'myArray' : 'struct' member redefinition. Добавление закомментировано в определении struct для Things выше. Однако, поскольку второе использование const UCHAR myArray[]; находится в названном union, компиляция работает, потому что второе использование доступно путем указания имени объединения.

person Richard Chambers    schedule 14.02.2016

Этот код здесь (https://gist.github.com/klange/4042963) показывает, как доступ к анонимным объединениям внутри структуры. Вы просто получаете доступ к членам вложенного объединения, как если бы они были членами структуры.

typedef struct {
    union {
        char * company;
        char * school;
        char * project;
    };
    union {
        char * location;
        char * url;
    };
    union {
        char * title;
        char * program;
    };

    time_t started;
    time_t left;

    char * description[];
} thing_t;

typedef thing_t job_t;

job_t yelp = {
    .company  = "Yelp, Inc.",
    .location = "San Francisco, CA",
    .title    = "Software Engineer, i18n",
    .started  = 1339977600,
    .left     = CURRENT,
    .description = {
        "Developed several internal tools and libraries",
        "Provided critical input and design work for Yelp's launch in Japan",
        NULL
    }
};
person Phani    schedule 17.03.2015

Имена, объявленные в анонимном объединении, используются напрямую, как переменные, не являющиеся членами. Хорошая причина сделать это - сэкономить память.

#include <iostream>

int main(int argc, char **argv) {
   union {
      double first;
      double second;
   };

   first = 10.001;
   second = 3.141592;
   std::cout << first << " " << second << std::endl;

   first = 10.002;
   std::cout << first << " " << second << std::endl;
}
person sciarp    schedule 29.11.2012
comment
если вы выложите результаты своего кода, это будет более полезно. (хотя мы можем запустить это сами) - person Brad Pitt; 10.01.2019

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

Объединения в основном используются для экономии памяти, и их размер равен наибольшему члену объединения.

А для доступа к полям данных объединения используйте оператор точки (.) так же, как и для структуры, как это описано в @Atmocreations. Когда значение присваивается одному члену, другие члены удаляются, поскольку они используют одну и ту же память.

в качестве примера, где могут быть полезны союзы, является

union time    
        {
        long time_in_sec;
        double time_in_mili_sec;
        }mytime;

.... Вышеупомянутое объединение можно использовать для хранения текущего времени (в секундах) или для сохранения времени с точностью до секунды. Или его можно использовать для измерения времени с точностью до миллисекунды. По-видимому, бывают случаи, когда вам нужно одно или другое, но не то и другое одновременно. Это объявление должно показаться вам знакомым. Это то же самое, что и определение структуры, но с ключевым словом union вместо struct.

для получения дополнительной информации http://msdn.microsoft.com/en-us/library/5dxy4b7b(v=vs.80).aspx

person akp    schedule 29.11.2012
comment
Для меня это наиболее полный ответ. Спасибо! - person zwx; 29.11.2012
comment
@akp: Обратите внимание. Выравнивание может нарушить это в зависимости от архитектуры - person Atmocreations; 29.11.2012
comment
Ответ неточный. Вопрос был об АНОНИМНОМ союзе, ответ - о союзе, имеющем название. - person Sergey Skopus; 27.12.2016
comment
Это не отвечает на вопрос. - person theEpsilon; 07.04.2017