如何在运行时按名称访问结构字段?
C faqs以某种方式解释它, 这里是链接。
但我无法理解,有人能为我解释一下吗? 或者给我另一种方式?
非常感谢!
我认为这个例子清楚地说明了答案:
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; }
你不能,不能没有自己实现某种名称查找。
程序运行时,C没有任何时间留下名称信息。
通常对不同的结构字段类型支持这一点很复杂。
如果您使用调试信息编译了二进制文件,则可以使用它在运行时查找名称。 例如, gcc
(通常)以DWARF格式生成调试信息,您可以使用libdwarf来处理它。
如果是DWARF,您可以在DW_TAG_member
节点中找到您的字段, DW_AT_data_member_location
属性将为您提供字段的偏移量,与在编译时从offsetof()
获得的相同。
跟踪使用offsetof()宏计算的字段偏移量。 如果structp是指向结构实例的指针,而字段f是具有偏移offsetf的int,则f的值可以间接设置
*(int *)((char *)structp + offsetf) = value;
如果使用struct {...}
定义定义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_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
,以便以它理解的某种forms标识运行时库的类型。
这样的宏几乎不漂亮,但它们的优点是可以确保它们用于定义的所有内容保持同步[例如,确保添加或删除acme_struct
的元素将导致它从struct列表中添加或删除成员存储在acme_struct_info
]中。