2010-04-08 29 views
0

是否有可能在不知道其成員變量的名稱的情況下訪問結構體或類的單個成員? 我想做一個「offsetof(struct,tyname)」,而不用將結構名稱或成員變量名稱硬編碼到其他東西中。 謝謝。在運行時訪問任何結構體成員

+3

你想要的東西一員,你不知道你不知道的某個名字。你認爲你可以用它做什麼?告訴我們你想做什麼,而不是你認爲你需要做什麼。 – GManNickG 2010-04-08 00:41:55

回答

4

當然。如果你有一個結構,並且你知道偏移量和成員變量的類型,你可以使用指針來訪問它。

struct my_struct { 
    int member1; 
    char member2; 
    short member3; 
    char member4; 
} 

... 

struct my_struct obj; 
short member3 = *((short*)((char*)&obj + 5)); 

這會得到member3的價值,這是從的obj x86的計算機上啓動5個字節。但是,你要小心。首先,如果結構發生變化,你的數據就會變成垃圾。我們到處都是,所以你沒有安全類型,如果出現錯誤,編譯器不會警告你。您還需要確保編譯器不包裝結構以將變量與字邊界對齊,否則偏移量將更改。

這不是一件愉快的事情,如果我是你,我會避免它,但是,是的,它可以完成。

+1

它可能是6個字節的偏移量 - 因爲'short'通常對齊2個字節的倍數。在你的結構中有幾個缺口,它可能是'sizeof(struct my_struct)== 12'。 – 2010-04-08 00:31:00

+0

是的,我剛剛寫了一個程序來查明,看起來你是對的。這是危險的:它通常*在2個字節的倍數上對齊,但並非總是如此。歡呼聲讓它透明。 – 2010-04-08 00:42:45

+2

自'sizeof(char)== 1'以來,您應該轉換爲char *'而不是'void *'。 C標準沒有定義'sizeof(void *)',所以用'void *'做指針運算是未定義的行爲。作爲一個擴展,gcc可以讓你用'sizeof(void *)== 1'來實現,但是當它這樣做的時候會發出警告。 – 2010-04-08 00:44:55

0

您的代碼中的某處需要引用結構中的數據成員。但是,您可以創建一個變量,該變量是一個指向結構數據成員的指針,從此不再需要按名稱引用它。

struct foo 
{ 
    int member1; 
    int member2; 
}; 

typedef int (foo::*intMemberOfFoo); 

intMemberOfFoo getMember() 
{ 
    if (rand() > RAND_MAX/2) return &foo::member1; 
    else return &foo::member2; 
} 

foo f; 
void do_somthing() 
{ 
    intMemberOfFoo m = getMember(); 
    f.*m = 0; 
} 
1

C和C++是沒有內置「反射」功能的編譯語言。這意味着無論你做什麼以及如何做,無論何種方式,路徑總是從一個明確的硬編碼值開始,即成員名稱或編譯時偏移值。這意味着如果你想基於某個運行時鍵選擇一個結構成員,你別無選擇,只能手動創建一種映射關鍵字值到標識具體結構成員的映射。

在C++中,爲了在運行時識別一個struct成員,你可以使用這個特性作爲指向成員的指針。在C中,唯一的選擇是使用偏移值。

另一個問題是,如果你的成員可以有不同的類型,那麼當然就要指定成員的類型。但你沒有提供任何細節,所以我不能說你是否需要處理它。

1

幾年前我們遇到了類似的問題:我們想要反思的一個龐大的配置信息結構。所以我們寫了一個Perl腳本,找到結構,解析其成員,並輸出看起來像一個C++文件:

struct ConfField 
{ const char* name; 
    int type; 
    size_t offset; 
}; 

ConfField confFields[] = { 
    { "version", eUInt32, 0 }, 
    { "seqID", eUInt32, 4 }, 
    { "timestamp", eUInt64, 8 }, 
    // ... lots more ... 
    { 0, 0, 0 } 
}; 

,我們會從gcc -E與輸出喂腳本。

現在,據我所知,gccxml可以輸出一個XML文件來代表gcc可以編譯的任何C++源代碼,因爲它實際上使用g ++前端來進行解析。所以我建議將它與XML解析腳本(我會使用Python與lxml庫)進行配對,以找出您想了解的有關C++源代碼的所有內容。

0

技術答案是'是',因爲C++是圖靈完備的,如果你足夠努力,你幾乎可以做任何事情。更實際的答案可能是'不',因爲沒有安全和簡單的方法來做你想要的東西。

我同意GMan。你究竟想要做什麼,讓你覺得你需要這種技術?

0

那麼你將不得不先設置一些東西,但它可以完成。擴大對薩米爾的響應

struct my_struct { 
    int member1; 
    char member2; 
    short member3; 
    char member4; 
} 

您可以創建偏移表:

my_struct tmp; 
int my_struct_offsets[4]={ 
    0, 
    (char*)&(tmp.member2)-(char*)&(tmp.member1), 
    (char*)&(tmp.member3)-(char*)&(tmp.member1), 
    (char*)&(tmp.member4)-(char*)&(tmp.member1) 
} 

這會考慮到不同的路線在不同的系統