0

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

Martin
  • 9
  • 1
  • 2
    Your code does make a pretty big mistake: It assumes that `sizeof(long) == 4`. That's not always the case. With the exception of `char` (where `sizeof(char) == 1` is always true), no built-in type in C have a fixed size. All you know is that `sizeof(char) <= sizeof(short) && sizeof(short) <= sizeof(int) && sizeof(int) <= sizeof(long) && sizeof(long) <= sizeof(long long)`. It's not uncommon for `sizeof(long) == 8` on 64-bit systems. – Some programmer dude Mar 19 '19 at 13:19
  • As for your problem, what *is* your problem? I means, what is the *original* problem that you try to solve? *Why* do you want to use `dummyVar` as a union? Why can't you just use plain bitwise operations (as in `uint32_t dummyVar = 0; dummyVar |= (some_value << 16);`)? – Some programmer dude Mar 19 '19 at 13:23
  • or more to the point, it *is* uncommon for `sizeof(long) == 4` on 64-bit systems (only on Windows!) – Antti Haapala -- Слава Україні Mar 19 '19 at 13:24
  • 1
    Although the size of a `char` defines the units in which other sizes are measured, even it does not have a fixed number of bits. – John Bollinger Mar 19 '19 at 13:26
  • 1
    `UPPER:16; /* [15:0] */` is just plain wrong no matter endianess. How do you know which 16 bits in the bit-field that are which bits anyway? It isn't specified by the C language. – Lundin Mar 19 '19 at 13:33
  • With all this casting, you should probably read about strict aliasing, for example here: https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – hyde Mar 19 '19 at 14:12

2 Answers2

1

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157