How to use c union nested in struct with no name

2019-02-08 12:40发布

问题:

I'm working on the so called Hotspot open source project, and looking at the implementation I found a nasty nested union in struct looking like that:

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;

As far as I'm aware in C/C++ that union is unaccesible. So how someone can make use of union declared in such manner and for what purpose?

Thanks!

回答1:

This is an anonymous union. In C++, as per [class.union], paragraph 5:

For the purpose of name lookup, after the anonymous union definition, the members of the anonymous union are considered to have been defined in the scope in which the anonymous union is declared

This means you can access its members as if they were members of RC_model_t_st.



回答2:

Without being sure and without having tried:

The union itself is not accessible, but it's members are.

Therefore you should be able to do refer to obj.block and obj.grid



回答3:

This code here (https://gist.github.com/klange/4042963) shows how to access anonymous unions inside struct. You just access the members of nested union as if they are members of the struct.

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
    }
};


回答4:

Names declared in an anonymous union are used directly, like nonmember variables. A good reason to do this is to save memory.

#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;
}


回答5:

To elaborate on the answer provided by Angew quoting the standard concerning anonymous unions and structs, I thought to provide an sample of C source code with the output generated by that sample showing how values are allocated within a struct and a union composed of struct and union components.

The standard quoted by Angew is:

For the purpose of name lookup, after the anonymous union definition, the members of the anonymous union are considered to have been defined in the scope in which the anonymous union is declared.

The source code of a struct composed of named and anonymous structs and unions looks like the following. This is using Visual Studio 2005 and the #pragma (pack, 1) is used to align everything on a char boundary in order for there to be no memory holes. There is also a simple C Preprocessor macro defined to make the output more legible and easier to code.

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;
}

The output generated by this function looks like:

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

The output shows the overlap between the various components of the main struct, Things caused by the use of unions. You can also see how the components of the anonymous struct and union are referenced versus those components of the named struct and union.

Also just for fun I tried adding an array definition of const UCHAR myArray[]; after the anonymous union containing const UCHAR myArray[]; to see what would happen. The compiler complained with an error of error C2020: 'myArray' : 'struct' member redefinition. The addition is commented out in the struct definition of Things above. However since the second use of const UCHAR myArray[]; is in a named union the compile works because second use is accessed by specifying the name of the union.



回答6:

first of all i want to say that A union, is a collection of variables of different types, just like a structure. However, with unions, you can only store information in one field at any one time.

The unions are basically used for memory saving & it's size is equal to the largest member of the union.

And for accessing the data fields of a union, use the dot operator(.) just as you would for a structure and explained by @Atmocreations. When a value is assigned to one member, the other member(s) get whipped out since they share the same memory.

as an example where the unions may be useful is

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

.... The union above could be used to either store the current time (in seconds) to hold time accurate to a second. Or it could be used to hold time accurate to a millisecond. Presumably there are times when you would want one or the other, but not both. This declaration should look familiar. It is the same as a struct definition, but with the keyword union instead of struct.

for more info http://msdn.microsoft.com/en-us/library/5dxy4b7b(v=vs.80).aspx