简体   繁体   English

按地址访问Struct中的元素

[英]Access elements in Struct by Address

I've done some research and I cant quite find what I'm looking for on here or google. 我已经进行了一些研究,但在这里或Google上找不到我想要的东西。 Is there a way to access the elements in a Customer by address (and not by using customer[i].bottles). 有没有一种方法可以通过地址(而不是通过使用customer [i] .bottles)访问Customer中的元素。 I cannot modify the struct so I cannot put the properties into an array. 我无法修改结构,因此无法将属性放入数组中。

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;
}

I thought I'd be able to do this but I got various errors. 我以为我可以做到这一点,但是我遇到了很多错误。 Knowing that the "bottles" value will be the second space in memory from the address of a Customer shouldn't i be able to directly set the spot. 我知道“瓶子”值将是客户地址在内存中的第二个空间,我不应该直接设置该位置。

I know this may be improper code but I would like to understand how and why does/doesnt work. 我知道这可能是不正确的代码,但是我想了解如何以及为什么/不起作用。 I also promise I have reasons for attempting to do this over the conventional way hah 我也保证我有理由尝试以传统方式做到这一点,哈哈

Instead of using propertyInd , perhaps pass an offset into the structure. 而不是使用propertyInd ,也许将偏移量传递到结构中。 That way, the code will work even if the layout changes dramatically (for example, if it includes non-int fields at the beginning). 这样,即使布局发生巨大变化(例如,如果开头包含非整数字段),代码也将起作用。

Here's how you might do it: 这是您可能的操作方式:

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

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

offsetof is a standardized macro that returns the offset, in bytes, from the start of the structure to the given element. offsetof是一个标准化的宏,它返回从结构开始到给定元素的偏移量(以字节为单位)。

If you still want to use indices, you can compute the offset as propertyInd * sizeof(int) , assuming every field in the struct is an int . 如果你仍然想使用指数,就可以计算偏移量为propertyInd * sizeof(int) ,假设在struct各个领域是一个int

You can't do this: 您不能这样做:

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

because the type of &customers[custInd] is struct Customer* , not int * . 因为&customers[custInd]的类型是struct Customer* ,而不是int * So &customers[custInd]+propertyInd means the same thing as &customers + custInd + propertyInd or, in other words, &customers[custInd + propertyInd] . 因此, &customers[custInd]+propertyInd&customers + custInd + propertyInd ,换句话说, &customers[custInd + propertyInd] The assignment then attempts to set a structure value to the integer 5 , which is obviously illegal. 然后,赋值尝试将结构值设置为整数5 ,这显然是非法的。

What I suppose you meant was 我想你的意思是

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

which would compile fine, and would probably work[*], but is undefined behaviour because you cannot assume that just because a struct consists of four int s, that it is laid-out in memory the same way as int[4] would be. 可以很好地编译,并且可能可以工作[*],但是它是未定义的行为,因为您不能仅假设结构由四个int组成,就将其布局在内存中的方式与int[4]相同。 It may seem reasonable and even logical that they layout be the same, but the standard doesn't require it, so that's that. 它们的布局相同似乎是合理的,甚至是合乎逻辑的,但是标准并不需要它,仅此而已。 Sorry. 抱歉。

As @iharob suggests in a comment, you might find a compiler clever enough to generate efficient code from the following verbiage: 就像@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);
  }
}

*: Actually, it would (probably) work if propertyInd for id were 0, not 1. C array indices start at 0. *:实际上,如果id propertyInd为0,而不是1,则(可能)有效。C数组索引从0开始。

&customers[custInd] is a pointer to customers[custInd] , so &customers[custInd]+propertyInd is a pointer to customers[custInd+propertyInd] . &customers[custInd]是指向customers[custInd]所以&customers[custInd]+propertyInd是一个指针,指向customers[custInd+propertyInd] It is not a pointer to a member. 它不是指向成员的指针。 It will have type pointer to Customer . 它将具有指向Customer类型指针。 The value of that pointer will be equal to &(customers[custInd+propertyInd].id) , but is not a pointer to int - hence the compiler error. 该指针的值将等于&(customers[custInd+propertyInd].id) ,但它不是指向int的指针-因此会出现编译器错误。

Your bigger problem is that four int in a struct are not necessarily laid out like an array of int - there may be padding between struct members. 您更大的问题是,结构中的四个int不一定像int数组那样进行布局-结构成员之间可能存在填充。 So, if we do 所以,如果我们这样做

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

then p+1 is not necessarily equal to &(customers[custInd].bottles) . 那么p + 1不一定等于&(customers[custInd].bottles)

So you will need to do something like 所以你需要做类似的事情

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM