2011-02-07 13 views
5

w celu C id jest typedef:Objective-C; typedef objc_object jako substytut id bez wskaźnika;

typedef struct objc_object { 
    Class isa; 
} *id; 

Mogę więc stwierdzenie, (i zainicjować) zmienną np tak:

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

Kompiluje dobrze.

Odkąd wymienić moje typy na własnym systemie, a ponieważ lubię domniemaną wskaźnik w id typedef chcę dodać własny typedef (z O do obiektu) tak:

typedef struct objc_object O; 

więc zmienną deklaracja (z inicjalizacji) mógłby wyglądać następująco:

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

To kompiluje z ostrzeżeniem:

inicjalizacja od I ncompatible wskaźnik typ

O ile mi zrozumieć typedefs myślałem, że ta ostatnia powinna być równa:

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

Które ponownie kompiluje grzywny.

To zdumiewające, że:

po_two = po_one; 
po_two = po_three; 

zarówno skompilować bez ostrzeżenia.

Tak próbowałem:

typedef struct objc_object * PO; 

aby sprawdzić, czy to działa bez ostrzeżenia, jeśli to wskaźnik (jest dokładnie co chcę uniknąć - tak po prostu ze względów testowych), aby zobaczyć, czy typedef poza definicja struktury działa inaczej niż typedef w definicji struktury (która jest definicją id w tym przypadku).

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

To również działa dobrze.

Jeśli używam:

#define O struct objc_object 

konstrukt korzystania O ponownie kompiluje bez ostrzeżenia.

Ale wolę używać maszyn typu "typedefs" zamiast definiowania, gdy tylko jest to możliwe.

Jestem zdziwiony. Jakie jest moje nieporozumienie z typedefs?

+0

Który kompilator? – JeremyP

+1

Można również użyć 'NSObject *' zamiast 'O *', np. 'NSObject * po_two = @" two ";', w większości przypadków. –

Odpowiedz

2

Nie jestem ekspertem od kompilatorów, więc prawdopodobnie prawdziwy ekspert może dać ci lepszą odpowiedź. W każdym razie, na podstawie mojej wiedzy, gdy kompilator dokonuje sprawdzenia typu, opiera to sprawdzanie na "drzewie analiz", które generuje tabelę dla wszystkich możliwych struktur typu danych i sprawdza, czy dwie definicje wskazują na ten sam wiersz na stole. Więc działa poprzez pobieranie symboli i definicji typów z tej tabeli i porównywanie ich. Teraz "struct objc_object" jest jedną z tych struktur danych.Następnie, gdy id jest zdefiniowany, generuje kolejny wpis: "id -> struct objc_object *". Definicja po_three prowadzi do tego samego odniesienia: "struct objc_object *" (infact "=" ma najniższy priorytet). To samo dzieje się w przypadku po_four, ponieważ PO prowadzi z definicji do tego samego odniesienia, ponownie (PO -> struct objc_object *). Gdy używasz definicji z #define, dzięki wstępnemu przetwarzaniu nadal odwołujesz się do "struct objc_object *". Ale kiedy używasz

O * po_two = @"two"
, w rzeczywistości próbujesz dopasować jeden typ, który jest "id" (@ "dwa"), to jest "struct objc_object *" i inny, który jest wskaźnikiem do "struct objc_object", ale nawet jeśli logicznie są takie same, ale nie prowadzą do tego samego odniesienia w tabeli. Powodem jest to, że typ "O" został już zdefiniowany, więc po_two jest po prostu zapisywane w tablicy symboli jako wskaźnik do "O" i "O -> struct objc_object". I to jest powód ostrzeżenia: po_two jest wskaźnikiem do czegoś innego niż @ "dwa".

Mam ciekawość: czy próbowałeś wykreślić tablicę symboli używając "nm"?

+0

Może być dobrym odgadnięciem z niedopasowanymi wpisami w tabeli. Próbowałem nm, ale nie dostarcza żadnych użytecznych informacji. Również debuger pokazuje te same typy - przynajmniej po inicjalizacji. W tej chwili domyślam się, że w gcc wbudowany jest hack, który umożliwia rzutowanie dowolnego wskaźnika na id. Ale może po prostu zapomnieli wziąć pod uwagę normalne reguły typu c (które powinny prowadzić do równoważnych typów dla id i O *) i dlatego typedef daje ostrzeżenie. – carpetemporem

+0

Tak, a to może wyjaśnić brakujące ostrzeżenie w po_two = po_three. – viggio24

Powiązane problemy