2010-03-25 41 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]中的結構成員列表。