union containing only one struct
Asked Answered
B

2

8

I have started today to program on a PIC16f88, and found that the header for its registers contains a union that only contains a struct:

extern volatile unsigned char ANSEL __at(0x09B);
typedef union {
    struct {
        unsigned ANS0       :1;
        unsigned ANS1       :1;
        unsigned ANS2       :1;
        unsigned ANS3       :1;
        unsigned ANS4       :1;
        unsigned ANS5       :1;
        unsigned ANS6       :1;
    };
} ANSELbits_t;
extern volatile ANSELbits_t ANSELbits __at(0x09B);

Does it provide any benefits to enclose the struct inside a union that only contains that struct?

Its access I guess is going to be exactly the same as if it were a simple struct (because the struct is anonymous):

ANSELbits.ANS4 = 0;

Benignity answered 27/1, 2019 at 15:58 Comment(4)
Would you mind confirming that you have or haven't omitted another member of the union?Funiculus
I copied exactly the code from the header. Nothing omitted.Benignity
Do other unions in the header have multiple elements? Are there any types in the header that are not unions? Maybe they just followed fixed pattern.Gorge
@Gorge Yes, there are unions with multiple elements. I suppose it's just that they followed a pattern.Benignity
F
2

It does not make any difference if you wrap and I suppose that someone has forgoten to add another member (or did not copy-paste everything) as in the declaration below. No warnings will be suppressed.

typedef union {
    struct {
        unsigned ANS0       :1;
        unsigned ANS1       :1;
        unsigned ANS2       :1;
        unsigned ANS3       :1;
        unsigned ANS4       :1;
        unsigned ANS5       :1;
        unsigned ANS6       :1;
    };
    uint8_t d8;
} ANSELbits_t;
extern volatile ANSELbits_t ANSELbits __at(0x09B);

BTW if the struct has to fit in 1 byte (8 bits) this declaration is wrong and uint_t type should be used instead.

Fustigate answered 27/1, 2019 at 16:6 Comment(0)
F
2

There is no benefit in standard portable C.

But code like this is used to circumvent (in a non-portable way) all the type checking that your C compiler will make.

You are then empowered to set all the members of the underlying struct in one go, which is useful in this case as it contains a lot of bit fields.

Funiculus answered 27/1, 2019 at 16:1 Comment(14)
any porability considerations are voided when I see extern volatile ANSELbits_t ANSELbits __at(0x09B); which is specific to Keil compiler used by some programmers in the uC programming (expensive and IMO not very good), but supported directly by ARMFustigate
@P__J__: Yes, that's a good point. It can only be to circumvent the type system then.Funiculus
In fact, I am using SDCC compiler. I suppose __at is being a macro to @Benignity
@CacahueteFrito: in which case I'm pretty convinced I'm correct. Remove the union and see what happens. Compiler warnings galore I'd expect.Funiculus
It will not. I think someone has forgotten another member, or just during the program development this member was not needed but programmer was too lazy to remove the wrapping union (very common in real life)Fustigate
@P__J__: Trust me, this is an old-fashioned idiom. Not much more I can say really!Funiculus
I am using MPLAB X, because of the teacher, and because I didn't find examples using Makefiles for that chip, but I added SDCC because I hate proprietary compilers and SDCC was the most closely related to GCC which is what I always used.Benignity
Trust me - will not change anything. Same warnings.Fustigate
For using all fields at once, it's clearly not, beacuse there is another variable that shares the same address, which is used for that (I updated the question with it just now)Benignity
@CacahueteFrito PIC uC? - my condolences :). LOL - the original programmer did not know how to use unions and has found this "workaround" :)Fustigate
Using bit-fields means the code is not portable, period. Almost everything about bit-fields is implementation-defined.Dorr
Oh, I accidentally opened the header of XC8, so this code is not used by SDCC. However the SDCC header still has the __at(). Also, the SDCC header does have another struct inside the union, so the only possible answer is that the XC8 programmers from uCheap were too lazy to clean the code.Benignity
Can you give an example of code that would "set all the members of the underlying struct in one go" given this definition? I can understand how you would do that if the union had another member, but as it is, I don't understand. (I also see that given the compiler-specific __at, presumably you can set all the fields by assigning to ANSEL, but that would seem to be the case whether the union is there or not.)Mattress
@Bathsheba: I'd also be interested in such an example.Decencies
F
2

It does not make any difference if you wrap and I suppose that someone has forgoten to add another member (or did not copy-paste everything) as in the declaration below. No warnings will be suppressed.

typedef union {
    struct {
        unsigned ANS0       :1;
        unsigned ANS1       :1;
        unsigned ANS2       :1;
        unsigned ANS3       :1;
        unsigned ANS4       :1;
        unsigned ANS5       :1;
        unsigned ANS6       :1;
    };
    uint8_t d8;
} ANSELbits_t;
extern volatile ANSELbits_t ANSELbits __at(0x09B);

BTW if the struct has to fit in 1 byte (8 bits) this declaration is wrong and uint_t type should be used instead.

Fustigate answered 27/1, 2019 at 16:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.