Home > database >  Do not access a variable through a pointer of an incompatible type?
Do not access a variable through a pointer of an incompatible type?

Time:11-05

I write some code like this:

typedef struct {
    uint8_t ms;
    uint8_t op;
    uint16_t len;
} DATA_HEAD;
static int data_rcv(uint8_t *rdt)
{
uint16_t op;
int op_king;
DATA_HEAD *pH;

pH = (DATA_HEAD *)rdt;
op_king= data_check(pH->op);
}
static int data_check(uint8_t op) {
//some code
}

I build and get this warning:

Accessing an object through a pointer pH whose type DATA_HEAD* is incompatible with the type of the object. Do not access a variable through a pointer of an incompatible type.

How to fix this warning? Thanks very much!

CodePudding user response:

I'm not quite sure what you're trying to do here, but I'm guessing the argument to the data_rcv function should take in a DATA_HEAD object or pointer, not a uint8_t. You should almost never be converting between pointers to completely different types like this. Also, there's no need to declare your variables before you use them; you can just do int op_king = data_check(...).

I see you've tagged your question with C , in which a more idiomatic way for this kind of code is using references. Anyway, hope this helps.

CodePudding user response:

What you try to archive is called "pointer punning". It generally should be avoided at any cost.

The safest method of punning types is use of the memcpy function.

typedef struct {
    uint8_t ms;
    uint8_t op;
    uint16_t len;
} DATA_HEAD;

static int data_rcv(void *rdt)
{
    int op_king;
    DATA_HEAD pH;

    memcpy(&pH, rdt, sizeof(pH));
    op_king= data_check(pH.len);
    return op_king;
}

memcpy function is well known to most modern optimizing compiler and in most circumstances, it will not be called.

In the example above the compiler will generate a simple load from the memory:

data_rcv:
        movzx   edi, WORD PTR [rdi 2]
        xor     eax, eax
        jmp     data_check

But if the architecture requires for example aligned access to some datatypes (like Cortex-M0)

data_rcv:
        push    {r4, lr}
        sub     sp, sp, #8
        add     r4, sp, #4
        movs    r1, r0
        movs    r2, #4
        movs    r0, r4
        bl      memcpy
        ldrh    r0, [r4, #2]
        bl      data_check
        add     sp, sp, #8
        pop     {r4, pc}

Protecting you from HardFaults if accesses are not properly aligned.

CodePudding user response:

How to fix this warning?

Supposing based on the function name and parameter type that all you have to start with is a byte array, and that you are supposing that the first four bytes map to the members of a DATA_HEAD (including correct byte order for op), the simplest thing to do for your particular example is to pick out the wanted bytes directly:

static int data_rcv(uint8_t *rdt) {
    uint16_t op;
    memcpy(&op, rdt   2, sizeof(op));

    int op_king = data_check(op);
}

The answer is similar if in reality you actually need to construct a complete DATA_HEAD for some other use:

static int data_rcv(uint8_t *rdt) {
    DATA_HEAD dh = { .ms = rdt[0], .op = rdt[1] };
    memcpy(&dh.op, rdt   2, sizeof(dh.op));

    int op_king = data_check(dh.op);

    // ...
}

Or if you need a DATA_HEAD whose lifetime extends beyond return from data_rcv(), then you can dynamically allocate it and set the members in similar manner.

What you cannot do (without eliciting the warning you present or a similar one), is reinterpret part of an array of bytes in-place as an object that is neither of character type nor of array-of-character type.

  • Related