简体   繁体   中英

Can we use pointer in union?

If no why? Uses of union over structure??

You can use any data type in a union, there's no restriction.

As to the use of unions over structures, structures lay out their data sequentially in memory. This mean all their sub-components are separate.

Unions, on the other hand, use the same memory for all their sub-components so only one can exist at a time.

For example:

                                 ┌─────┬─────┐
struct { int a; float b }  gives │  a  │  b  │
                                 └─────┴─────┘
                                    ▲     ▲
                                    │     │
                 memory location:  150   154
                                    │
                                    ▼
                                 ┌─────┐
union { int a; float b }  gives  │  a  │
                                 │  b  │
                                 └─────┘

Structures are used where an "object" is composed of other objects, like a point object consisting of two integers, those being the x and y coordinates:

typedef struct {
    int x;           // x and y are separate
    int y;
} tPoint;

Unions are typically used in situation where an object can be one of many things but only one at a time, such as a type-less storage system:

typedef enum { STR, INT } tType;
typedef struct {
    tType typ;          // typ is separate.
    union {
        int ival;       // ival and sval occupy same memory.
        char *sval;
    }
} tVal;

They are useful for saving memory although that tends to be less and less of a concern nowadays (other than in low-level work like embedded systems) so you don't see a lot of it.

Well, according to ISO/IEC 9899:TC3 (the C99 standard):

A union type describes an overlapping nonempty set of member objects, each of which has an optionally specified name and possibly distinct type.

In short, the memory space of union members overlaps, and the names you give to union members allow you to read memory at that location in size. Consider:

#include <stdio.h>
#include <stdint.h>

typedef union
{
    struct
    {
        uint8_t a;
        uint8_t b;
        uint8_t c;
        uint8_t d;
    };
    uint32_t x;
} somenewtype;

typedef union
{
    uint32_t* p;
    uint8_t* q;
} somepointer;

int main(int argc, char** argv)
{
    uint32_t r;
    uint8_t s;
    somenewtype z;
    somepointer p;
    r = 0x11223344; s = 0x11;
    z.x = 0x11223344;
    p.p = &r;
    p.q = &s;
    printf("%x%x%x%x\n", z.d, z.c, z.b, z.a);
    printf("%x %x\n", *(p.p), *(p.q));
}

In the first printf, what we're doing is printing out 8-bit parts of the 32-bit integer. Hoping of course for no padding in that anonymous struct.

In the second printf? I had to step through using gdb to understand, but I did:

p.p = (uint32_t *) 0x7fffffffde5c;
p.q =  (uint8_t *) 0x7fffffffde5b "\021D3\"\021P\337\377\377\377\177";
p.p = (uint32_t *) 0x7fffffffde5b;

Well of course, pointers are all the same size, so assigning pq overwrites the address of pp . I suspect strongly that de-referencing the address of the 32-bit integer to an 8-bit pointer is printing "whatever is at that location + 32 bits in size" which co-incidentally for me happens to be 22334411 . But I suspect, at that point, the behaviour is undefined.

Anyway, the point of that little exercise was to show you that:

  • unions can be used to access the same memory location through a different "type" modifier.
  • You have to be careful what you do and understand the underlying type you're using. If you're going to use pointers, beware their modification as you might start pointing to who knows what.

I should point out I can see the practical use for somenewtype but not for somepointer - that was a contrived example I was pretty sure would break.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM