答案 0 :(得分:6)
我认为这个例子清楚地说明了答案:
struct test
{
int b;
int a;
};
int main()
{
test t;
test* structp = &t;
//Find the byte offset of 'a' within the structure
int offsetf = offsetof(test, a);
//Set the value of 'a' using pointer arithmetic
*(int *)((char *)structp + offsetf) = 5;
return 0;
}
答案 1 :(得分:1)
你不能,不能没有自己实现某种名称查找。
当程序运行时,C没有任何时间留下名称信息。
通常对不同的结构字段类型支持这一点很复杂。
答案 2 :(得分:1)
如果您使用调试信息编译了二进制文件,则可以使用它在运行时查找名称。例如gcc
(通常)以DWARF格式生成调试信息,您可以使用libdwarf来处理它。
如果是DWARF,您可以在DW_TAG_member
节点中找到您的字段,DW_AT_data_member_location
属性将为您提供字段的偏移量,与您在编译时从offsetof()
获得的相同。
答案 3 :(得分:0)
跟踪使用offsetof()宏计算的字段偏移量。如果structp是指向结构实例的指针,并且字段f是具有偏移offsetf的int,则可以使用
间接设置f的值*(int *)((char *)structp + offsetf) = value;
答案 4 :(得分:0)
如果使用struct {...}
定义定义结构,则可执行代码中不可能存在与成员名称相关的任何信息。一些平台将“调试”信息构建到生成的可执行文件中,并且可能有一些方法可以使正在运行的程序检索该信息,但是没有通用的方法来执行此类操作。
但是,可以使用宏来定义结构。例如,可以定义:
#define MAKE_ACME_STRUCT \
FIELD(id,int,23) \
X FIELD(name,char30,"Untitled") \
X FIELD(info,int,19) \
// LEAVE THIS COMMENT HERE
然后多次调用MAKE_ACME_STRUCT宏,并且FIELD和X宏定义了不同的方式,以便它可以扩展为struct语句,或者扩展为该结构的“默认”实例的初始化表达式,或者作为描述struct字段的项数组的初始化表达式[例如
之类的东西STRUCT_INFO acme_struct_info[] = {
{"id", STRUCT_INFO_TYPE_int, sizeof(ACME_STRUCT.id), offsetof(ACME_STRUCT.id)}
,{"name", STRUCT_INFO_TYPE_char30, sizeof(ACME_STRUCT.name), offsetof(ACME_STRUCT.name)}
,{"info", STRUCT_INFO_TYPE_int, sizeof(ACME_STRUCT.info), offsetof(ACME_STRUCT.info)}
,{0}};
结构中使用的所有类型都必须具有单令牌名称,并且对于每个这样的名称,必须定义标识符STRUCT_INFO_TYPE_nameGoesHere
,以某种形式标识运行时库的类型它理解。
这些宏并不漂亮,但它们的优势在于确保它们用于定义的所有内容保持同步[例如确保添加或删除acme_struct
元素会导致在acme_struct_info
]中存储的struct成员列表中添加或删除它。