按地址访问结构中的元素

Access elements in Struct by Address

我做了一些研究,但我无法在此处或 google 上完全找到我要找的东西。有没有办法通过地址访问 Customer 中的元素(而不是使用 customer[i].bottles)。我无法修改结构,因此无法将属性放入数组中。

typedef struct Customer {
  int id;
  int bottles;
  int diapers;
  int rattles;
} Customer;

Customer customers[100];

void setValue(int custInd, int propertyInd) {
  //propertyInd would be 1 for id, 2 for bottles
  //Attempting to set customers[0].bottles
  *(&customers[custInd]+propertyInd) = 5;
}

我以为我可以做到这一点,但我遇到了各种错误。知道 "bottles" 值将是内存中来自客户地址的第二个 space,我不应该能够直接设置点。

我知道这可能是不正确的代码,但我想了解 does/doesnt 的工作原理和原因。我也保证我有理由尝试通过传统方式做到这一点 hah

而不是使用 propertyInd,也许将偏移量传递到结构中。这样,即使布局发生显着变化(例如,如果它在开头包含非整数字段),代码也能正常工作。

您可以这样做:

void setValue(int custInd, int fieldOffset) {
    int *ptr = (int *)((char *)&customers[custInd] + fieldOffset);
    *ptr = 5;
}

...
setValue(custInd, offsetof(Customer, bottles));

offsetof 是一个标准化宏,它 returns 从结构开始到给定元素的偏移量(以字节为单位)。

如果您仍想使用索引,可以将偏移量计算为 propertyInd * sizeof(int),假设结构中的每个字段都是 int.

你不能这样做:

*(&customers[custInd]+propertyInd) = 5;

因为&customers[custInd]的类型是struct Customer*,不是int *。所以 &customers[custInd]+propertyInd&customers + custInd + propertyInd&customers[custInd + propertyInd] 的含义相同。然后赋值尝试将结构值设置为整数 5,这显然是非法的。

我想你的意思是

((int*)&customers[custInd])[propertyInd] = 5;

可以很好地编译,并且可能会工作[*],但它是未定义的行为,因为你不能假设仅仅因为一个结构由四个 int 组成,它就在内存中布局与 int[4] 相同的方式。它们的布局相同似乎合理甚至合乎逻辑,但标准并不要求它,仅此而已。对不起。

正如@iharob 在评论中建议的那样,您可能会发现编译器足够聪明,可以根据以下措辞生成高效代码:

void setValue(int custInd, int propertyInd, int value) {
  //propertyInd would be 1 for id, 2 for bottles
  switch (propertyInd) {
    case 1: customers[custInd].id = value; break;
    case 2: customers[custInd].bottles = value; break;
    case 3: customers[custInd].diapers = value; break;
    case 4: customers[custInd].rattles = value; break;
    default: assert(0);
  }
}

*:实际上,如果 idpropertyInd 为 0 而不是 1,它(可能)会起作用。C 数组索引从 0 开始。

&customers[custInd]是指向customers[custInd]的指针,所以&customers[custInd]+propertyInd是指向customers[custInd+propertyInd]的指针。它不是指向成员的指针。它将具有指向 Customer 的类型指针。该指针的值将等于 &(customers[custInd+propertyInd].id),但不是指向 int 的指针 - 因此编译器错误。

你更大的问题是结构中的四个 int 不一定像 int 的数组一样布局 - 结构成员之间可能有填充。所以,如果我们这样做

int *p = &(customers[custInd].id);

那么p+1不一定等于&(customers[custInd].bottles).

所以你需要做类似

的事情
void setValue(int custInd, int Offset)
{
    int *ptr = (int *)(((char *)&customers[custInd]) + Offset);
    *ptr = 5;
}

/*  and to call it to set customers[custInd].bottles to 5 */

setValue(custInd, offsetof(Customer, bottles));