【问题标题】:What is correct way to access a struct using pointer and offsetof()使用指针和 offsetof() 访问结构的正确方法是什么
【发布时间】:2019-10-30 10:42:40
【问题描述】:

我有以下代码,以便能够访问结构数组中的多个字段(为简单起见,我将其减少到两个)。最终指针计算的正确咒语是什么 *(ptr + offset) = data; 因为我总是得到:

错误:从类型“int32_t”{aka“int”}分配给类型“struct osc_in_data”时类型不兼容

#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)

【问题讨论】:

  • struct osc_in_data *ptr; -->> char *ptr; [用于原始指针算术] 而且:你需要一些丑陋的演员表......
  • 有充分的理由使用offsetof 与知道正确使用它之间存在高度相关性。

标签: c struct offsetof


【解决方案1】:

成员具有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】:

    offsetoff 函数告诉您同一结构内 2 个内存地址之间的字节距离。

    使用下面的代码,

       *(ptr + offset) = data;
    

    struct osc_in_data指针做指针运算,与ptr[offset] = data;相同

    你可以尝试的是。

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

    【讨论】:

    • @MikeBryant 如果您使用 C++ 编译器进行编译,它不应该给出警告。这个解决方案也更正确——另一个答案中提到的解决方案由于严格的别名规则而具有未定义的行为。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多