2

I have the following code so as to be able to access numerous fields in array of structs (I've reduced it to two for simplicity). What is the correct incantation for the final pointer calculation *(ptr + offset) = data; because I always get :

error: incompatible types when assigning to type ‘struct osc_in_data’ from type ‘int32_t’ {aka ‘int’}

#define NumHarmonics   10

int32_t data1;
int32_t data2;



struct osc_in_data                                                           
{
    int32_t     LevelAttackRate;                                                
    int64_t     LevelPeakLevel;                                                 
    int32_t     LevelDecayRate;                                                 
} OscControl[NumHarmonics];



void SetADSRvalues(int32_t offset, int32_t data)
{
    int32_t harmonic;
    struct osc_in_data *ptr;
    for (harmonic = 0; harmonic < NumHarmonics; harmonic++)
    {
       ptr = &OscControl[harmonic];
       *(ptr + offset) = data;
    }
} 


SetADSRvalues(offsetof(struct osc_in_data, LevelAttackRate), data1)
SetADSRvalues(offsetof(struct osc_in_data, LevelDecayRate), data2)
Mike Bryant
  • 310
  • 2
  • 12

2 Answers2

4

The offsetoff function tells you the distance in bytes between 2 memory adresses inside the same structure.

With below code you are telling,

   *(ptr + offset) = data;

do pointer arithmetic on struct osc_in_data pointer, that is same as ptr[offset] = data;

Instead what you can try is.

memcpy((char *)ptr + offset, data, sizeof data);
kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
  • 1
    @MikeBryant It shouldn't give a warning if you're compiling with a C++ compiler. This solution is also more correct -- the solution mentioned in the other answer has undefined behavior due to the strict aliasing rule. – S.S. Anne Oct 30 '19 at 11:10
3

The members have int32_t type so pointers to them are int32_t*.

The offsetof(...) is just the offset in bytes. So you just take the pointer to the structure which member you want to modify. Then add to the pointer the offset using plain addition and remembering to use char* pointers to add one byte at a time. Then just cast the pointer to proper type and dereference and access it.

void SetADSRvalues(size_t offset, int32_t data)
{
    for (size_t harmonic = 0; harmonic < NumHarmonics; harmonic++) {
          // take the pointer to the structure we want to modify
          void *base = &OscControl[harmonic];
          // arithmetic using void* pointers is invalid
          // so convert to `char*` pointer before arithmetic
          char *basechar = base;
          // then add the offset - just plain addition
          // results in the address of the member inside the struct
          void *memberpnt = basechar + offset;
          // the member is `int32_t`, so the pointer has to be `int32_t*`
          int32_t *memberpnt_int32 = memberpnt;
          // finally set the value
          *memberpnt_int32 = data;

          // or a oneliner version:
          *(int32_t*)((char*)&OscControl[harmonic] + offset) = data;
    }
} 
KamilCuk
  • 120,984
  • 8
  • 59
  • 111