2012-12-31 85 views
4

考慮一個具有兩個整數類型成員的結構。我想通過地址獲得兩位成員。我可以成功獲得第一名,但第二名我得到錯誤的價值。我相信這是垃圾價值。這裏是我的代碼:通過地址訪問結構成員

#include <stdio.h> 

typedef struct { int a; int b; } foo_t; 

int main(int argc, char **argv) 
{ 

    foo_t f; 
    f.a = 2; 
    f.b = 4; 
    int a = ((int)(*(int*) &f)); 
    int b = ((int)(*(((int*)(&f + sizeof(int)))))); 
    printf("%d ..%d\n", a, b); 
    return 0; 
} 

我越來越:

2 ..1

有人能解釋其中我已經錯了嗎?

+0

爲什麼你不這樣做在'int a'的聲明中,就像'int a = f.a;'一樣?你正在「訪問結構」,好像它是分配內存一樣,但顯然你不是! – t0mm13b

+0

@ t0mm13b:目的 - 學習.. – Jack

回答

7

C標準中第一個成員的偏移量必須始終爲零;這就是爲什麼你的第一個演員工程。然而,由於填充,第二個構件的偏移量可能不一定等於該結構的第一個構件的大小。

此外,向指針添加數字並不會將字節數添加到地址:相反,將添加指向的東西的大小。因此,當您將sizeof(int)添加到&f時,將添加sizeof(int)*sizeof(foo_t)

您可以使用offsetof運營商如果想自己做數學題,這樣

int b = *((int*)(((char*)&f)+offsetof(foo_t, b))); 

之所以這樣工作原理是,sizeof(char)總是之一,所要求的C標準。

當然,您可以使用&f.b來避免手動進行數學運算。

+0

不是'offsetof'非標準GCC擴展? – Dolda2000

+2

@ Dolda2000不,這是ANSI C:見7.17.3 [這裏](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf); – dasblinkenlight

+0

你確定嗎?即使現在看到GCC手冊,它也會在其C擴展名下列出'offsetof'。當然,之後它可能已經在標準中被定義。 – Dolda2000

1

你可以做&f.b,並跳過實際的指針數學。

這是我如何會改變你的int b行:

int b = (int)(*(((int*)(&(f.b))))); 

BTW,當我運行程序的是,我得到2 ..0作爲輸出。

+0

它是UB,也許? – Jack

1

這工作:

int b = ((int)(*(int*)((int)&f + sizeof(int)))); 

您正在解釋&˚F作爲一個指針,當要添加4(INT的大小),它會將其解釋爲添加4個指針是根據16或32個字節在32和64拱。如果你將指針轉換爲int,它將正確地向它添加4個字節。

這是對正在發生的事情的解釋。我不確定你在做什麼,但你絕對不應該這樣做。這可以讓你在與定位等安全的方式找出麻煩結構元素的偏移量爲:

printf("%d\n", &(((foo_t *)NULL)->b)); 
+0

'((int)&f + sizeof(int))'將對具有sizeof(int *)> sizeof(int)'的系統造成嚴重破壞。除非編譯器在成員之間添加填充,否則'(int *)&f + 1'或'(uintptr_t)&f + sizeof(int)'將起作用。 –

2

你的問題是&f + sizeof(int)。如果A是一個指針,並且B是一個整數,則在C中,A + B不意味着A加上B字節。相反,這意味着AB元素,其中元素的大小由指針類型A定義。因此,如果sizeof(int)在您的體系結構上爲4,那麼&f + sizeof(int)意味着「四個foo_t s到&f或4 * 8 = 32個字節到&f」。

嘗試((char *)&f) + sizeof(int)

或者,當然,&f.a&f.b相反,很簡單。後者不僅可以給你提供方便的指針,而且可以幫助你減輕所有這些表演的負擔,同時也是明確的,可以理解的。 :)

2

表達式&f + sizeof(int)將數字添加到類型爲foo_t*的指針。指針算術總是假定指針指向數組的一個元素,並且該數字被視爲元素的數量。

所以,如果sizeof(int)是4,&f + sizeof(int)點中的四個foo_t結構過去f,或&f4*sizeof(foo_t)字節。

如果必須使用字節數,這樣的事情可能工作:

int b = *(int*)((char*)(&f) + sizeof(int)); 

...假設有成員ab之間沒有填充。

但是,有沒有什麼原因,你不只是得到的價值f.b或指針&f.b