题
让我说我有这个结构:
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结构的成员
编辑:寻找问题的解决方案而不是另一种方法。
解决方案
鉴于只有一个widgit *而不是一个widgit **被传递到dialKey,没有办法做你想要的(widgit *值与NUMBER_KEY结构没有关系)。假设你的意思是:
void dialKey(widget** ppWidget)
{
// Need to print 'num' of the struct that this widget resides in
}
微软有一个很棒的宏来做这种事情(它有助于能够在C中通用操作链接列表):
#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);
其他提示
迈克尔在他的回答中解释说,你不能用给定的约束来做,因为没有办法“走回来”。指针图。为了使事情更加明显,让我绘制一个对象图(用C语言表示,而不是OOP意义上):
+- NUMBER_KEY --+
| ... | points to
| widget field -+-----------+
| ... | |
+---------------+ | + widget +
+-->| ... |
| ... |
+-->| ... |
| +--------+
points to |
[widget argument]-----------+
注意箭头。它们是单向的 - 你可以“走路”。从指向指向值的指针,但你不能“走路”背部。所以你可以使用你的函数的 widget
参数来获取 widget
对象,但是一旦那里,就没有办法告诉别人指向它 - 包括<的任何实例代码> NUMBER_KEY 结构。想想看:如果你有其他几十个指向同一小部件
的指针,其中一些指针来自不同的 NUMBER_KEY
对象怎么办?如果不保留 widget
对象中所有指针的列表,它怎么可能跟踪呢?如果你真的需要这个,那就是你需要做的 - 让 widget
指向它自己的 NUMBER_KEY
。
结构的内存布局由编译器定义,只有在struct成员之间有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'
C标准定义 offsetof()
宏(在 stddef.h
标题中定义),这在您的情况下很方便。
#include <stddef.h>
void DialKey(widget** foo) {
printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}
请注意,您必须传递结构字段的地址,而不是值!
最安全的解决方案是在小部件中保持指向相关nKey结构的指针
printf("%d", widget->myKey->num);
所有其他方法都不安全