2009-07-30 35 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))); 
} 

请注意,你必须通过一个地址结构域的,而不是一个值!