2010-03-25 44 views

回答

5

我觉得这个例子使得答案明确:

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; 

} 
+0

我认为值得指出的是,“名称”(a)在这里是一个编译时符号,而不是“在运行时”找到的东西。在后一种情况下,它必须是一个字符串,并且offsetof()不起作用。 – unwind 2010-03-25 15:13:12

1

你不能,没有实现某种名称查找自己。

程序运行时C没有任何时间留下名称信息。

通常为不同的结构体字段类型提供支持是很复杂的。

1

如果你有你的二进制编译带有调试信息,你可以用它在运行时查找名称。例如,gcc(通常)以DWARF格式生成调试信息,您可以使用libdwarf来处理它。

在矮的情况下,你可以找到在DW_TAG_member节点所在领域,DW_AT_data_member_location属性会给你场的偏移,和你一样从offsetof()得到在编译时。

0

记录使用offsetof()宏计算的字段偏移量。如果structp是指向该结构的一个实例,字段f是具有偏移offsetf一个int中,f的值可以间接地与

*(int *)((char *)structp + offsetf) = value; 
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宏不同的时间,用领域和X宏定义不同的方法,使得其将扩大要么一个结构声明,或用于初始化表达式该结构的“默认”实例,或作为描述结构字段的项目数组的初始化表达式[例如像

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]中的结构成员列表。