структура 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
Редактировать:ищу решение проблемы, а не другой метод.
Решение
Учитывая, что только widgit *, а не widgit ** передается в dialKey, нет никакого способа сделать то, что вы хотите (значение widgit * не имеет отношения к структуре NUMBER_KEY). Предполагая, что вы действительно имеете в виду что-то вроде:
void dialKey(widget** ppWidget)
{
// Need to print 'num' of the struct that this widget resides in
}
У Microsoft есть изящный макрос для таких вещей (он помогает иметь возможность подпрограмм, которые обычно управляют связанными списками в 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, а не в смысле ООП):
+- NUMBER_KEY --+
| ... | points to
| widget field -+-----------+
| ... | |
+---------------+ | + widget +
+-->| ... |
| ... |
+-->| ... |
| +--------+
points to |
[widget argument]-----------+
Обратите внимание на стрелки. Они односторонние - вы можете "гулять" от указателя к указанному значению, но вы не можете " ходить " назад. Таким образом, вы можете задержать аргумент widget
своей функции, чтобы получить доступ к объекту widget
, но, находясь там, невозможно определить, кто еще указывает на это, включая любые экземпляры < code> NUMBER_KEY . Подумайте об этом: что если у вас есть дюжина других указателей на один и тот же виджет
, некоторые из них из разных объектов NUMBER_KEY
? Как он может отслеживать это, не сохраняя список всех указателей в объекте widget
? Если вам это действительно нужно, это то, что вам нужно сделать - заставить widget
указать на принадлежащий ему NUMBER_KEY
.
Структура памяти структуры определяется вашим компилятором, ваш код будет работать только в том случае, если у вас есть 0-байтовое заполнение между элементами структуры.Обычно это не рекомендуется, поскольку при заполнении 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);
Все остальные методы небезопасны