如何通过偏移获取/设置结构成员
忽略填充/对齐问题并给出以下结构,在不使用成员名称的情况下获取和设置member_b的值的最佳方法是什么。
struct mystruct { int member_a; int member_b; } struct mystruct *s = malloc(sizeof(struct mystruct));
换一种方式; 你如何用指针/偏移来表达以下内容:
s->member_b = 3; printf("%i",s->member_b);
我的猜测是
- 通过查找member_a(
int
)的size来计算偏移量 - 将结构转换为单个单词指针类型(
char
?) - 创建一个
int
指针并设置地址(到*charpointer + offset
?) - 使用我的
int
指针来设置内存内容
但是我对于转换为char类型有点困惑,或者如果像memset
这样的东西更合适,或者通常我正在处理这个完全错误。
欢呼任何帮助
你概述的方法大致是正确的,虽然你应该使用offsetof
而不是试图找出你自己的偏移量。 我不确定你为什么提到memset
– 它将一个块的内容设置为一个指定的值,这似乎与手头的问题无关。
编辑:演示代码:
#include #include #include typedef struct x { int member_a; int member_b; } x; int main() { x *s = malloc(sizeof(x)); char *base; size_t offset; int *b; // initialize both members to known values s->member_a = 1; s->member_b = 2; // get base address base = (char *)s; // and the offset to member_b offset = offsetof(x, member_b); // Compute address of member_b b = (int *)(base+offset); // write to member_b via our pointer *b = 10; // print out via name, to show it was changed to new value. printf("%d\n", s->member_b); return 0; }
完整的技术:
-
使用offsetof获取偏移量:
b_offset = offsetof(struct mystruct,member_b);
-
获取结构的地址作为char *指针。
char * sc =(char *)s;
-
添加将偏移量添加到结构地址,将值转换为指向相应类型的指针并取消引用:
*(int *)(sc + b_offset)
忽略填充和对齐,如你所说……
如果您指向的元素完全属于单个类型(如示例中所示),则可以将结构转换为所需类型并将其视为数组:
printf("%i", ((int *)(&s))[1]);
可以根据struct和NULL计算偏移量作为参考指针,例如“ &(((type *)0) – > field) ”
例:
struct my_struct { int x; int y; int *m; int *h; }; int main() { printf("offset %d\n", (int) &((((struct my_struct*)0)->h))); return 0; }
在此特定示例中,您可以通过*((int *) ((char *) s + sizeof(int)))
。 我不确定你为什么要那样,所以我假设有教学目的,因此解释如下。
代码位转换为:从地址s开始占用内存并将其视为指向char
内存。 到该地址,添加sizeof(int)
char
-chunks – 您将获得一个新地址。 获取由此创建的地址的值并将其视为int
。
注意写*(s + sizeof(int))
将给出s
加上sizeof(int)
sizeof(mystruct)块的地址
编辑:根据Andrey的评论,使用offsetof :
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
编辑2:我用char
s替换了所有byte
s,因为sizeof(char)
保证为1。
从您的评论中可以看出,您真正在做的是将一堆不同的数据类型打包并解压缩到一个内存块中。 虽然您可以通过直接指针转换来实现这一点,但大多数其他答案都建议:
void set_int(void *block, size_t offset, int val) { char *p = block; *(int *)(p + offset) = val; } int get_int(void *block, size_t offset) { char *p = block; return *(int *)(p + offset); }
问题是这是不可移植的。 没有通用的方法来确保类型以正确的对齐方式存储在块中,并且某些体系结构根本无法对未对齐的地址进行加载或存储。 在块的布局由声明的结构定义的特殊情况下,它将是正常的,因为struct布局将包括必要的填充以确保正确的对齐。 但是,由于您无法按名称访问成员,因此听起来这实际上并不是您正在做的事情。
要以便携式方式执行此操作,您需要使用memcpy
:
void set_int(void *block, size_t offset, int val) { char *p = block; memcpy(p + offset, &val, sizeof val); } int get_int(void *block, size_t offset) { char *p = block; int val; memcpy(&val, p + offset, sizeof val); return val; }
(与其他类型相似)。