0

I have an array of unsigned 16-bit integers:

static uint16_t dataArray[7];

The bits of the 7th element of the array represents some kind of status. I want to get and set the values of this status in an easy way, without bit shifting and without having to copy a new value to the array every time the status changes. So I created a union with a struct, and a pointer:

typedef struct {
        unsigned statusCode     : 4;
        unsigned errorCode      : 4;
        unsigned outputEnabled  : 1;
        unsigned currentClip    : 1;
        unsigned                : 6;
} SupplyStruct_t;

typedef union {
    SupplyStruct_t s;
    uint16_t value;
} SupplyStatus_t;

static SupplyStatus_t * status;

My initialisation routine wants the status pointer to point to the 7th element of the array, so I tried:

status = &(dataArray[6]);

Although this works, I get a warning: assignment from incompatible pointer type

Is there a better way to do this? I cannot change the array, but I am free to change the structure, the union or the pointer to the array..

2
  • 1
    of course they are incompatible and the warning is correct. Declare daraArray as table of unions or cast it . Commented Jul 24, 2018 at 10:03
  • I can not change the array.. I want a struct or union or.. to easily change the uint16_t value of the array. How would I do a cast? Commented Jul 24, 2018 at 10:05

2 Answers 2

1
  1. Change unsigned to uint16_t

why? - test the difference: https://ideone.com/uHLzpV

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

typedef struct {
        uint16_t statusCode     : 4;
        unsigned errorCode      : 4;
        unsigned outputEnabled  : 1;
        unsigned currentClip    : 1;
        unsigned                : 6;
} SupplyStruct_t;

typedef struct {
        uint16_t statusCode     : 4;
        uint16_t errorCode      : 4;
        uint16_t outputEnabled  : 1;
        uint16_t currentClip    : 1;
        uint16_t                : 6;
} SupplyStruct_t1;


typedef union {
    SupplyStruct_t s;
    uint16_t value;
} SupplyStatus_t;

typedef union {
    SupplyStruct_t1 s;
    uint16_t value;
} SupplyStatus_t1;

int main(void) {
    printf("%zu %zu\n", sizeof(SupplyStatus_t), sizeof(SupplyStatus_t1));
    return 0;
}

The most correct way is to declare the table as table of structs.

If not :

If you want too work on the bitfields you do not actually have to declare the pointer.

static SupplyStatus_t status;
status.value = dataArray[6];

and it is almost portable and safe way

you can also cast it explicitly

Sign up to request clarification or add additional context in comments.

4 Comments

But when I would change the values of the status struct, it would not change the value of the element in the array.
you can cast it as I wrote in the comment but it is not conforming C. BTW always check if your union has the size you think it has. See the ideone example in my answer
Yes I see the difference now!
Why is it not conforming? It certainly isn't strictly conforming, but only a tiny fraction of C programs are. The Standard explicitly says that portability is not a requirement for conformance.
0

The warning says that uint16_t* is not compatible with SupplyStatus_t*. If you want to get rid of this warning, cast it to SupplyStatus_t*:

status = (SupplyStatus_t*)&(dataArray[6]);

I also would put the union and struct together:

typedef union
{
  struct
  {
    unsigned statusCode : 4;
    unsigned errorCode : 4;
    unsigned outputEnabled : 1;
    unsigned currentClip :1;
    unsigned unused : 6;
  } s;
  uint16_t value;
} SupplyStatus_t;

7 Comments

It is wrong my fiend. try status++ and see if if does what you think.
I assume the pointer would go the next address in the array? However for this particular case, the pointer will never change. It may be better to declare it like this: static SupplyStatus_t * const status = (SupplyStatus_t*)&(dataArray[6]);
Not only is this wrong, even if things were "correct" it would still be a strict aliasing violation. Making errors and warnings disappear by forcefully casting a value is a really bad idea.
Well, I just tried the code and it works. If you call status.value++ the value in dataArray will be increased. In this situation, the cast is necessary and not a bad idea - how else could you assign a union to a specific type without a cast?
will be increased but by how many elements of the array (one or two - what do you think)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.