c struct datos de captura por desplazamiento
Pregunta
Digamos que tengo esta estructura:
typedef struct nKey {
int num;
widget* widget;
} NUMBER_KEY;
y una función:
void dialKey(widget* widget) {
// Need to print 'num' of the struct that this widget resides in
}
¿Cómo hago para lograr esto? Intenté algo como:
printf("%d", * (int *) widget - sizeof(int)); // Failure.org
editar: es seguro asumir que el widget que se pasa es, de hecho, miembro de una estructura NUMBER_KEY
editar: buscando una solución al problema, no otro método.
Solución
Dado que solo se pasa un widgit * y no un widgit ** a dialKey, no hay forma de hacer lo que desea (un valor widgit * no tiene relación con la estructura NUMBER_KEY). Asumiendo que realmente quieres decir algo como:
void dialKey(widget** ppWidget)
{
// Need to print 'num' of the struct that this widget resides in
}
Microsoft tiene una macro ingeniosa para hacer este tipo de cosas (ayuda a poder tener rutinas que manipulen las listas vinculadas genéricamente en C):
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
Puedes usar esto así:
NUMBER_KEY* pNumberKey = CONTAINING_RECORD( *ppWidgit, NUMBER_KEY, widgit);
printf( "%d", pNumberKey->num);
Otros consejos
Como explica Michael en su respuesta, no puede hacerlo con las restricciones dadas porque no hay forma de "caminar de regreso". El gráfico del puntero. Para hacer las cosas más obvias, permítanme dibujar un diagrama de los objetos (en términos de C, no en sentido POO) involucrados:
+- NUMBER_KEY --+
| ... | points to
| widget field -+-----------+
| ... | |
+---------------+ | + widget +
+-->| ... |
| ... |
+-->| ... |
| +--------+
points to |
[widget argument]-----------+
Observe las flechas. Son unidireccionales: puedes 'caminar'. de un puntero al valor en punta, pero no puede "caminar" espalda. Por lo tanto, puede deducir el argumento widget
de su función para llegar al objeto widget
, pero una vez allí, no hay forma de saber quién más lo señala, incluidas las instancias de < code> NUMBER_KEY estructuras. Piénselo: ¿qué pasaría si tuviera una docena de otros punteros al mismo widget
, algunos de ellos de diferentes objetos NUMBER_KEY
? ¿Cómo podría rastrear eso sin mantener una lista de todos los punteros dentro del objeto widget
? Si realmente necesita esto, es lo que tendrá que hacer: hacer que el widget
apunte a su NUMBER_KEY
.
El diseño de memoria de una estructura está definido por su compilador, su código solo funcionaría si tiene 0 bytes de relleno entre los miembros de la estructura. Por lo general, esto no se recomienda porque el relleno de byte de 0 bytes tendría su estructura superpuesta en los tamaños de lectura estándar de la mayoría de los procesadores.
Algunas macros útiles para su problema:
#define GET_FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#define GET_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
ejemplo:
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 define la macro offsetof ()
(definida en el encabezado stddef.h
), que es útil en su caso.
#include <stddef.h>
void DialKey(widget** foo) {
printf("%d", *((char *)foo - offsetof(struct nKey, widget)));
}
Tenga en cuenta que debe pasar una dirección del campo de estructura, ¡no un valor!
La solución más segura es mantener el puntero a la estructura nKey relacionada en el widget
printf("%d", widget->myKey->num);
Todos los demás métodos son inseguros