Home > other >  Pointer arithmetic with "inherited" structs is returning unexpected values
Pointer arithmetic with "inherited" structs is returning unexpected values

Time:01-25

I'm trying to create multiple structs in C with one "base" struct type representing multiple types of objects:

#include <stdio.h>
#include <sys/types.h>

enum parent_type{
    parent_type_1,
    parent_type_2
};

struct Child{
    int size_bytes;
};

struct Parent1{
    struct Child base;
    u_int16_t val;
};

struct Parent2{
    struct Child base;
    u_int8_t val;
};

void readParentData(struct Child* toread){
    printf("Byte size: %d\n", toread->size_bytes);
    int val_read = *((u_int16_t*)((&toread)   sizeof(struct Child)));
    printf("Value: %d\n", val_read);
}

struct Parent1 p1;

int main(){
    p1.val = 1000;

    p1.base.size_bytes = 2;

    struct Parent1* p1_p = &p1;

    struct Child* child_p = (struct Child*)p1_p;

    readParentData(child_p);
}

I would expect readParentData() to output 1000, but instead it is outputting random values. I get the correct output if i cast the pointer to a Parent1 pointer: printf("Cast value: %d\n", ((struct Parent1*)(toread))->val); but this won't work if I have to use the function for other structs, like Parent2. I've also tried using the offsetof() function but that gives the same result as my original pointer arithmetic: int val_read = *((u_int16_t*)((&toread) offsetof(struct Parent1, val)));

I would expect that adding the size of a struct to its pointer gives the address of the next values in the "Parent" struct, but this is apparently not the case.

CodePudding user response:

((&toread) sizeof(struct Child))) is offsetting the address of toread by sizeof(struct Child). You need to offset what toread points to by sizeof(struct Child). Additionally, offsetting toread by sizeof(struct Child) adds sizeof(struct Child) * sizeof(struct Child) to toread. To offset toread by the size of 1 child, you need to add 1 to it. What you need to do for this to work is

void readParentData(struct Child* toread){
    printf("Byte size: %d\n", toread->size_bytes);
    int val_read = *((u_int16_t*)(toread   1));
    printf("Value: %d\n", val_read);
}

But this is not a good way to do it. If you want to read the parent data, you should just cast the pointer to a struct Parent1* and read it directly

void readParentData(struct Child* toread){
    printf("Byte size: %d\n", toread->size_bytes);
    int val_read = ((struct Parent1*)(toread))->val;
    printf("Value: %d\n", val_read);
}
  • Related