Martin
Martin

Reputation: 9

Cast a variable to union-type defined within a structure definition

Actually I have some difficulties in C to cast an unsigned int variable to a union-type which is declared within the declaration of structure type.

I need to set a variable in the same way like writing the field of a union defined in a structure.

Declaration in included header file:

typedef struct {
    [...]

    union {
        unsigned long COMPLETE_VALUE;
        struct {
            unsigned long   UPPER:16;           /* [15:0] */
            unsigned long   LOWER:16;           /* [31:16] */
        } SUB_STRUCT;
    } UNION;

    [...]
} STRUCT_TYPE;

Variable in c-source file:

STRUCT_TYPE *pStructure;                        /* the reference structure */
unsigned long dummyVar;                         /* dummy variable */

/* writing the upper field in the structure */
pStructure->UNION.SUB_STRUCT.UPPER = some_value;

Question: It is possible to modify the value of "dummyVar" using the internal union-types of the structure-type STRUCT_TYPE? Is it possible to cast the variable to the union defined within the structure and accessing the field of the sub-structure?

It would be really useful if the variable could be modified like shown below or in a similar way:

((<CAST>) dummyVar).UNION.SUB_STRUCT.UPPER = some_value;

Notes: - The declaration of STRUCT_TYPE cannot be changed. - The structure pStructure cannot be written or edited. - The access behavior of pStructure needs to reproduced to dummyVar.

Is this possible in C anyway?

Thank you in advance!

Martin

Upvotes: 0

Views: 126

Answers (2)

John Bollinger
John Bollinger

Reputation: 180211

It is possible to modify the value of "dummyVar" using the internal union-types of the structure-type STRUCT_TYPE?

All consideration of sizes and representations notwithstanding, no, it is not possible to cast anything to the internal union type in your example, because typecasts are only applicable to scalar types. There are games you could play with pointers and brittle code duplication, but I strongly advise against such shenanigans, and I decline to present an example.

However, if you want to set the value of dummyVar to a value corresponding to STRUCT_TYPE.UNION.COMPLETE_VALUE for some particular values of UPPER and LOWER, then in C99 and later you can do so via a compound literal:

dummyVar = ((STRUCT_TYPE) { .UNION = { .SUB_STRUCT = { some_upper, some_lower } } }).UNION.COMPLETE_VALUE;

Note well that although the (STRUCT_TYPE) piece resembles a cast, it is rather just a part of the syntax of a compound literal. You cannot cast to a structure type any more than you can cast to a union type.

Alternatively, in translation units where STRUCT_TYPE is not defined, you could write a compound literal for the internal union type, but it would be much worse. Since that type has no tag or alias, a compound literal of that type would need to reproduce its complete definition. The type of such a compound literal is not technically compatible with that of the structure member in any translation unit where both are defined, but as a practical matter, I don't see any reason to doubt that you would get the same value for dummyVar either way.

Upvotes: 1

Lundin
Lundin

Reputation: 213791

It is possible to modify the value of "dummyVar" using the internal union-types of the structure-type STRUCT_TYPE?

Probably not, since you have this:

typedef struct {
    [...]

    union {

I assume [...] means there are struct members placed there.

Is it possible to cast the variable to the union defined within the structure and accessing the field of the sub-structure?

Not unless it is the initial part of the struct and even then it is questionable. It would perhaps have been smarter to break out the union as a separate typedef that isn't tightly coupled to the struct.

In addition, the bit-fields used by the union aren't standardized and you can't know how they end up in memory, portably.

The smart thing to do here is probably to forget all about the struct and simply do

uint32_t u32 = ...
uint16_t ms = u32 >> 16;
uint16_t ls = u32 & 0xFFFFu;

This code is portable regardless of bit-field implementations and endianess.

Upvotes: 1

Related Questions