2013-09-05 8 views
6

In un programma C Ho una structQuando è legale digitare type-pun usando un puntatore a puntatore in C?

typedef struct { 
    void *payload; // opaque, real type known to callbacks 

     ... some stuff ... 
} MiddleMan; 

di creare qualche parvenza di tipo di sicurezza che potrei creare getter e setter

CbData *get_cb_data(const MiddleMan *mm){ return mm->payload; } 
void set_cb_data(MiddleMan *mm, CbData *cbd){ mm->payload = cbd; } 

Oppure posso provare a farlo con una sola, puntatore di accesso basata su

CbData **cb_data(MiddleMan *mm){return (CbData**)&mm->payload;} 

ora la seconda soluzione sembra dodgier rispetto alla prima, e limita inoltre agli utenti di non-const mm anche se o voglio solo leggere. Ma la mia domanda è se è addirittura legale C?

Sono abbastanza sicuro che è possibile farla franca su qualsiasi architettura in cui lo void* è della stessa dimensione del formato & come CbData*. Ma qualcuno può dare un chiaro ragionamento sul perché questo sia (o non sia) valido in generale?

+1

Questo è legale in C. 'void *' e 'CbData *' sono sempre della stessa dimensione - entrambi sono di tipo puntatore. Scusa ma non capisco perché ci sia una domanda sulla validità di questa implementazione di "**" che hai scritto sopra. –

+3

Su alcune architetture bizzarre, la dimensione dei puntatori varia a seconda di cosa indicano. 'void *' dovrebbe essere abbastanza grande da coprire tutte le possibilità, ma 'CbData *' può essere più piccolo, a seconda di cosa sia effettivamente 'CbData'. –

+0

puoi per favore dare qualche esempio di quelle strane architetture? Davvero curioso –

risposta

4

Generalmente, non dovresti farlo. Un void** potrebbe avere i diversi requisiti di allineamento con CbData**. Un cast esplicito può produrre il diverso indirizzo.

standard C 6.2.5.27:

Un puntatore a void avrà la stessa rappresentazione e allineamento requisiti un puntatore a una type.39 carattere) Analogamente, puntatori alle versioni qualificato o non qualificato di compatibili i tipi devono avere gli stessi requisiti di rappresentazione e allineamento. Tutti i puntatori ai tipi di struttura devono avere la stessa rappresentazione e allineamento i requisiti tra loro. Tutti i puntatori ai tipi di unione devono avere lo stesso requisiti di allineamento e di rappresentazione reciproci. I puntatori ad altri tipi non devono avere la stessa rappresentazione o allineamento requisiti.

+0

tuttavia dice 6.3.2.3: "Un puntatore a void può essere convertito in o da un puntatore a qualsiasi tipo incompleto o oggetto . Un puntatore a qualsiasi tipo incompleto o di oggetto può essere convertito in un puntatore per annullare e viceversa; il risultato deve essere paragonato al puntatore originale. ... non si applicherebbe qui? – msam

+0

Fin qui sembra corretto, ma sto aspettando altre opinioni prima di accettarlo. Poiché 'void *' è il tipo di puntatore più generale, 'void **' avrà l'allineamento più stretto, e quindi il cast in '(CbData **)' sarà un puro re-intrepret. La mia ipotesi è che la cosa sia illegale, ma funziona anche sulle architetture più strane. –

+0

@msam che sta parlando di conversioni di tipo esplicito tra valori di puntatore, mentre sto punendo sull'indirizzo di quei puntatori.Ecco perché le cose non sono chiare. –

Problemi correlati