按地址访问结构中的元素
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);
}
}
*:实际上,如果 id
的 propertyInd
为 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));
我做了一些研究,但我无法在此处或 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);
}
}
*:实际上,如果 id
的 propertyInd
为 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));