Как правильно получить доступ к структуре с помощью указателя и offsetof () - PullRequest
0 голосов
/ 30 октября 2019

У меня есть следующий код, чтобы иметь доступ к многочисленным полям в массиве структур (для простоты я сократил его до двух). Что такое правильное заклинание для окончательного вычисления указателя *(ptr + offset) = data;, потому что я всегда получаю:

ошибка: несовместимые типы при назначении типу 'struct osc_in_data' из типа '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)

Ответы [ 2 ]

3 голосов
/ 30 октября 2019

Элементы имеют тип int32_t, поэтому указатели на них int32_t*.

offsetof(...) - это просто смещение в байтах. Таким образом, вы просто берете указатель на структуру, член которой вы хотите изменить. Затем добавьте к указателю смещение с помощью простого сложения и не забывайте использовать указатели char* для добавления одного байта за раз. Затем просто приведите указатель на правильный тип и разыменование и получите к нему доступ.

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;
    }
} 
2 голосов
/ 30 октября 2019

Функция offsetoff сообщает вам расстояние в байтах между 2 адресами памяти внутри одной и той же структуры.

С указанным ниже кодом,

   *(ptr + offset) = data;

делать арифметику указателей на struct osc_in_data указатель, такой же, как ptr[offset] = data;

Вместо этого вы можете попробовать:

memcpy((char *)ptr + offset, data, sizeof data);
...