2011-02-07 9 views
5

in Objective-C ID è un typedef:Objective-C; typedef objc_object come sostituto dell'ID senza puntatore;

typedef struct objc_object { 
    Class isa; 
} *id; 

così posso dichiarare (ed inizializzare) una variabile di esempio in questo modo:

// using id 
id po_one = @"one"; 

compila bene.

Dal momento che il nome del mio tipi in un proprio schema e dal momento che non mi piace il puntatore implicito nel id typedef voglio aggiungere una propria typedef (con O per oggetto) in questo modo:

typedef struct objc_object O; 

Quindi una variabile dichiarazione (con l'inizializzazione) potrebbe apparire come:

// using O 
O * po_two = @"two"; 

Questo compila con un avvertimento:

inizializzazione da puntatore ncompatible tipo

Per quanto ho capito typedef ho pensato che quest'ultimo dovrebbe essere equivalente a:

// using struct objc_object 
struct objc_object * po_three = @"three"; 

che compila bene di nuovo.

E 'sorprendente che:

po_two = po_one; 
po_two = po_three; 

sia compilare senza avvertimenti.

Così ho provato:

typedef struct objc_object * PO; 

per vedere se funziona senza preavviso se includo il puntatore (essendo esattamente la cosa che voglio evitare - in modo solo per motivi di prova) per verificare se un typedef al di fuori di la definizione della struttura funziona in modo diverso rispetto a un typedef nella definizione della struttura (che in questo caso è la definizione di id).

// using PO 
PO po_four = @"four"; 

che funziona anche bene.

Se uso:

#define O struct objc_object 

costrutto usando O compila ancora una volta senza preavviso.

Ma preferisco usare typedefs invece di una definizione quando possibile.

Sono confuso. Qual è la mia incomprensione con typedef?

+0

Quale compilatore? – JeremyP

+1

Inoltre, potresti usare 'NSObject *' invece di 'O *', ad es. 'NSObject * po_two = @" two ";', nella maggior parte dei casi. –

risposta

2

Non sono un esperto di compilatori, quindi probabilmente un vero esperto può darti una risposta migliore. In ogni caso, in base alle mie conoscenze, quando un compilatore esegue il controllo dei tipi, basa questo controllo sull'albero di analisi, che genera una sorta di tabella per tutte le possibili strutture di tipi di dati e controlla se due definizioni puntano alla stessa riga sul tavolo. Quindi funziona recuperando i simboli e le definizioni dei tipi da questa tabella e confrontandoli. Ora "struct objc_object" è una di queste strutture dati.Quindi, quando viene definito id, viene generata un'altra voce: "id -> struct objc_object *". La definizione po_three porta allo stesso riferimento: "struct objc_object *" (infatti "=" ha la precedenza più bassa). Lo stesso accade per po_four, perché PO conduce per definizione allo stesso riferimento, di nuovo (PO -> struct objc_object *). Quando si utilizza la definizione con #define, grazie alla pre-elaborazione si sta ancora riferendo a "struct objc_object *". Ma quando si utilizza

O * po_two = @"two"
si sta in effetti cercando di far corrispondere un tipo che è "id" (@ "due"), cioè "struct objc_object *" e un altro che è un puntatore a "struct objc_object" ma anche se logicamente sono gli stessi non portano allo stesso riferimento nella tabella. Il motivo è perché il tipo "O" è stato ancora definito, quindi po_two viene semplicemente memorizzato nella tabella dei simboli come puntatore a "O" e "O -> struct objc_object". E questo è il motivo dell'avvertimento: po_two è un puntatore a qualcosa di diverso da @ "due".

Ho una curiosità: hai provato a tracciare la tabella dei simboli usando "nm"?

+0

Potrebbe essere una buona ipotesi con le voci della tabella di corrispondenza errata. Ho provato nm ma non fornisce informazioni utili. Anche il debugger mostra solo gli stessi tipi - almeno dopo l'inizializzazione. La mia piccola ipotesi al momento è che c'è un hack incorporato in gcc che abilita qualsiasi puntatore a essere castato all'id. Ma forse si sono semplicemente dimenticati di considerare normali regole di tipo c (che dovrebbero portare a tipi equivalenti per id e O *) e quindi il typedef restituisce l'avvertimento. – carpetemporem

+0

Sì, e questo potrebbe spiegare l'avviso mancante in po_two = po_three. – viggio24

Problemi correlati