C语言 如何通过偏移量获取/设置结构成员
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2043871/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I get/set a struct member by offset
提问by Chris Farmiloe
Ignoring padding/alignment issuesand given the following struct, what is best way to get and set the value of member_b without using the member name.
忽略填充/对齐问题并给出以下结构,在不使用成员名称的情况下获取和设置 member_b 值的最佳方法是什么。
struct mystruct {
int member_a;
int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));
Put another way; How would you express the following in terms of pointers/offsets:
换一种方式; 您将如何用指针/偏移量表达以下内容:
s->member_b = 3;
printf("%i",s->member_b);
My guess is to
我的猜测是
- calculate the offset by finding the sizeof the member_a (
int) - cast the struct to a single word pointer type (
char?) - create an
intpointer and set the address (to*charpointer + offset?) - use my
intpointer to set the memory contents
- 通过查找 member_a (
int)的大小来计算偏移量 - 将结构强制转换为单字指针类型 (
char?) - 创建一个
int指针并设置地址(到*charpointer + offset?) - 使用我的
int指针设置内存内容
but I get a bit confused about casting to a char type or if something like memsetis more apropriate or if generally i'm aproching this totally wrong.
但是我对转换为 char 类型感到有些困惑,或者如果类似的东西memset更合适,或者我通常完全错误地处理这个问题。
Cheers for any help
为任何帮助干杯
回答by Jerry Coffin
The approach you've outlined is roughly correct, although you should use offsetofinstead of attempting to figure out the offset on your own. I'm not sure why you mention memset-- it sets the contents of a block to a specified value, which seems quite unrelated to the question at hand.
您概述的方法大致正确,尽管您应该使用offsetof而不是尝试自己计算偏移量。我不确定你为什么提到memset——它将块的内容设置为指定的值,这似乎与手头的问题无关。
Here's some code to demonstrate how it works:
下面是一些代码来演示它是如何工作的:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
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;
}
回答by R Samuel Klatchko
The full technique:
完整技术:
Get the offset using offsetof:
b_offset = offsetof(struct mystruct, member_b);
Get the address of your structure as a char * pointer.
char *sc = (char *)s;
Add the add the offset to the structure address, cast the value to a pointer to the appropriate type and dereference:
*(int *)(sc + b_offset)
使用 offsetof 获取偏移量:
b_offset = offsetof(struct mystruct, member_b);
以 char * 指针的形式获取结构的地址。
char *sc = (char *)s;
添加将偏移量添加到结构地址,将值转换为指向适当类型的指针并取消引用:
*(int *)(sc + b_offset)
回答by mskfisher
Ignoring padding and alignment, as you said...
忽略填充和对齐,正如你所说......
If the elements you're pointing to are entirely of a single type, as in your example, you can just cast the structure to the desired type and treat it as an array:
如果您指向的元素完全是单一类型,如在您的示例中,您可以将结构转换为所需的类型并将其视为数组:
printf("%i", ((int *)(&s))[1]);
回答by Obik
It's possible calculate the offset based on the struct and NULL as reference pointer e.g " &(((type *)0)->field)"
可以根据结构和 NULL 作为引用指针计算偏移量,例如“ &(((type *)0)->field)”
Example:
例子:
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;
}
回答by laura
In this particular example, you can address it by *((int *) ((char *) s + sizeof(int))). I'm not sure why you want that, so I'm assuming didactic purposes, therefore the explanation follows.
在此特定示例中,您可以通过*((int *) ((char *) s + sizeof(int))). 我不确定你为什么想要那样,所以我假设教学目的,因此解释如下。
The bit of code translates as: take the memory starting at address s and treat it as memory pointing to char. To that address, add sizeof(int)char-chunks - you will get a new address. Take the value that the address thus created and treat it as an int.
这段代码翻译为:取从地址 s 开始的内存,并将其视为指向 的内存char。向该地址添加sizeof(int)char-chunks - 您将获得一个新地址。取地址由此创建的值并将其视为int.
Note that writing *(s + sizeof(int))would give the address at splus sizeof(int)sizeof(mystruct) chunks
请注意,写入*(s + sizeof(int))将在s加上sizeof(int)sizeof(mystruct) 块处给出地址
Edit: as per Andrey's comment, using offsetof:
编辑:根据安德烈的评论,使用offsetof:
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
Edit 2: I replaced all bytes with chars as sizeof(char)is guaranteed to be 1.
编辑 2:我用bytes替换了所有s,char因为sizeof(char)保证为 1。
回答by caf
It sounds from your comments that what you're really doing is packing and unpacking a bunch of disparate data types into a single block of memory. While you canget away with doing that with direct pointer casts, as most of the other answers have suggested:
从您的评论中可以看出,您真正在做的是将一堆不同的数据类型打包和解包到一个内存块中。虽然您可以通过直接指针转换来避免这样做,但正如大多数其他答案所建议的那样:
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);
}
The problem is that this is non-portable. There's no general way to ensure that the types are stored within your block with the correct alignment, and some architectures simply cannot do loads or stores to unaligned addresses. In the special case where the layout of your block is defined by a declared structure, it will be OK, because the struct layout will include the necessary padding to ensure the right alignment. However since you can't access the members by name, it sounds like this isn't actually what you're doing.
问题是这是不可移植的。没有通用的方法来确保类型以正确的对齐方式存储在您的块中,并且某些架构根本无法对未对齐的地址进行加载或存储。在块的布局由声明的结构定义的特殊情况下,这将是可以的,因为结构布局将包括必要的填充以确保正确对齐。但是,由于您无法按名称访问成员,因此听起来这实际上并不是您在做什么。
To do this portably, you need to use memcpy:
要便携地执行此操作,您需要使用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;
}
(similar for the other types).
(其他类型类似)。

