Pergunta

Digamos que eu tenho esta estrutura:

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

e uma função:

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

Como faço para fazer isso? Eu tentei algo como:

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

EDIT: É seguro supor que o widget que está sendo passado é de fato um membro de uma estrutura número_key

EDIT: Procurando uma solução para o problema, não outro método.

Foi útil?

Solução

Dado apenas um widgit* e não um widgit ** sendo transmitido para o Dialkey, não há como fazer o que você deseja (um valor de widgit* não tem relação com o número_key struct). Supondo que você realmente queira dizer algo como:

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

A Microsoft tem uma macro bacana para fazer esse tipo de coisa (ajuda a poder ter rotinas que manipulam listas vinculadas genéricas em c):

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

Você poderia usar isso assim:

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

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

Outras dicas

Como Michael explica em sua resposta, você não pode fazê -lo com determinadas restrições, porque não há como "voltar" o gráfico do ponteiro. Para tornar as coisas mais óbvias, deixe -me desenhar um diagrama de objetos (em termos c, não no sentido do OOP) envolvidos:

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

Observe as setas. Eles são de mão única - você pode "caminhar" de um ponteiro para um valor pontudo, mas não pode "voltar". Então você pode deferência widget argumento de sua função para chegar ao widget objeto, mas uma vez lá, não há como dizer quem mais aponta para ele - incluindo quaisquer instâncias de NUMBER_KEY estruturas. Pense bem: e se você tivesse uma dúzia de outros ponteiros para o mesmo widget, alguns deles de diferentes NUMBER_KEY objetos? Como poderia rastrear isso sem manter uma lista de todos os ponteiros dentro widget objeto? Se você realmente precisa disso, é o que você terá que fazer - faça widget apontar para o seu próprio NUMBER_KEY.

O layout da memória de uma estrutura é definido pelo seu compilador, seu código só funcionaria se você tivesse 0 bytes preenchido entre os membros da estrutura. Geralmente, isso não é recomendado que o preenchimento de bytes b/c 0 teria sua sobreposição de estrutura nos tamanhos de leitura padrão da maioria dos processadores.

Algumas macros úteis para o seu problema:

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

exemplo:

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 Standard define offsetof() macro (definido em stddef.h cabeçalho), que é útil no seu caso.

#include <stddef.h>

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

Observe que você tem que passar um Morada de campo Struct, não um valor!

A solução mais segura é manter o ponteiro para a estrutura de Nkey relacionada no widget

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

Todos os outros métodos são inseguros

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top