2009-07-30 81 views
0

抓取數據可以說我有這樣的結構:C結構由偏移

typedef struct nKey { 
    int num; 
    widget* widget; 
} NUMBER_KEY; 

和功能:

void dialKey(widget* widget) { 
    // Need to print 'num' of the struct that this widget resides in 
} 

我如何去實現呢?我想是這樣的:

printf("%d", * (int *) widget - sizeof(int)); // Failure.org 

編輯:它是安全的假設,所傳遞的控件實際上是一個NUMBER_KEY結構

編輯的成員:尋找一個解決問題的方法不是另一種方法。

+0

您的代碼不會一定按原樣工作,因爲在結構的成員之間可能存在實現定義的填充。 – 2009-07-30 20:01:30

+0

重要的是指針指向的是小部件,而不是指向小部件的指針。此外,從(int *)中減去sizeof(int)將指針移回sizeof(int)ints,而不僅僅是一個。更不用說填充的可能性了。 – 2009-07-30 20:57:02

回答

4

僅給定一widgit *,而不是**被傳遞到dialKey一個widgit,就沒有辦法做你想要(widgit *值與NUMBER_KEY結構沒有關係)。假設你真的是這樣的:

void dialKey(widget** ppWidget) 
{  
    // Need to print 'num' of the struct that this widget resides in 
} 

微軟做這種類型的事情一記漂亮的宏(它有助於能夠有操縱用C鏈表genericly例程):

#define CONTAINING_RECORD(address, type, field) ((type *)(\ 
           (PCHAR)(address) - \ 
           (ULONG_PTR)(&((type *)0)->field))) 

您可以使用此像這樣:

NUMBER_KEY* pNumberKey = CONTAINING_RECORD(*ppWidgit, NUMBER_KEY, widgit); 

printf("%d", pNumberKey->num); 
-1

最安全的辦法是保持指針相關NKEY結構部件

printf("%d", widget->myKey->num); 

其他所有方法都是不安全的

+0

「所有其他方法都是不安全的」這是大膽的誇大。 – qrdl 2009-07-31 13:37:27

5

正如邁克爾在他的回答解釋了,你不能在給定約束做到這一點,因爲沒有方式來「走回」指針圖。爲了讓事情變得更明顯,讓我繪製對象的圖(在C組術語,而不是面向對象的意義上)參與:

+- NUMBER_KEY --+ 
| ...   | points to  
| widget field -+-----------+ 
| ...   |   | 
+---------------+   | + widget + 
          +-->| ... | 
           | ... | 
          +-->| ... | 
          | +--------+ 
        points to | 
[widget argument]-----------+ 

通知箭頭。它們是單向的 - 你可以從一個指針「走」到指定值,但是你不能「走回」。因此,您可以將函數的參數widget轉換爲widget對象,但一旦出現,就無法告訴其他人指向它 - 包括任何NUMBER_KEY結構的實例。想一想:如果你有十幾個其他的指向同一個widget的指針,其中一些指針來自不同的NUMBER_KEY對象?如何在不保留widget對象內的所有指針列表的情況下跟蹤該問題?如果你真的需要這個,那就是你必須要做的 - 讓widget指向它擁有的NUMBER_KEY

0

結構的內存佈局是由您的編譯器定義的,您的代碼只有在結構成員之間有0字節填充時纔有效。通常這是不推薦的b/c 0字節填充會使你的結構覆蓋大多數處理器的標準讀取大小。

你的問題的一些有用的宏:

#define GET_FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field)) 
#define GET_FIELD_SIZE(type, field)  (sizeof(((type *)0)->field)) 

例如:

NUMBER_KEY key; 
key.num = 55; 
int nOffSetWidget = GET_FIELD_OFFSET(NUMBER_KEY, widget); 
int *pKeyNumAddress = (int *) &(key.widget) - nOffSetWidget); 

printf("%d", * pKeyNumAddress); // Should print '55' 
+0

如果#include ,offsetof()宏是標準的。 – 2009-07-30 20:44:22

0

C標準定義offsetof()宏(在stddef.h頭文件中定義),這是在你的情況下派上用場。

#include <stddef.h> 

void DialKey(widget** foo) { 
    printf("%d", *((char *)foo - offsetof(struct nKey, widget))); 
} 

請注意,你必須通過一個地址結構域的,而不是一個值!