2013-09-05 7 views
6

W programie C Mam structKiedy można legalnie pisać przy użyciu wskaźnika do wskaźnika w C?

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

     ... some stuff ... 
} MiddleMan; 

Aby stworzyć pewne pozory typu bezpieczeństwa mógłbym stworzyć pobierające i ustawiające

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

Albo mogę spróbować zrobić to z jednym, wskaźnik -na accessor

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

obecnie drugim rozwiązania wygląda dodgier niż pierwszy, a także ogranicza użytkowników do const mm nawet jeśli oni o raczej chcę czytać. Ale moje pytanie brzmi, czy to nawet legalne C?

Jestem prawie pewien, że możesz sobie z tym poradzić w każdej architekturze, w której void* ma ten sam rozmiar co format & jako CbData*. Ale czy ktoś może jasno uzasadnić, dlaczego jest on (lub nie jest) w ogóle ważny?

+1

Jest to legalne w C. 'void *', a 'CbData *' są zawsze tego samego rozmiaru - oba są typu wskaźnika. Przepraszam, ale nie rozumiem, dlaczego istnieje pytanie dotyczące ważności tej "**" wersji, którą napisałeś powyżej. –

+3

W niektórych dziwnych architekturach rozmiar wskaźników zmienia się w zależności od tego, co wskazują. 'void *' powinno być wystarczająco duże, aby pokryć wszystkie możliwości, ale 'CbData *' może być mniejsze, w zależności od tego, czym jest 'CbData'. –

+0

czy możesz podać przykłady tych dziwnych architektur? Naprawdę ciekawy. –

Odpowiedz

4

Generalnie nie powinieneś tego robić. A void** może mieć różne wymagania dotyczące wyrównania z CbData**. Wyraźna obsada może wytworzyć inny adres.

C średnia 6.2.5.27:

Wskaźnik do unieważnienia mają taką samą reprezentację i wyrównanie Wymogi jako wskaźnik do type.39 znaków) Podobnie wskaźniki uprawnionych lub niewykwalifikowanych wersje kompatybilne typy muszą mieć takie same wymagania odwzorowania i wyrównania. Wszystkie wskaźniki dla typów konstrukcji muszą mieć takie same wymagania odwzorowania i wyrównania, jak siebie nawzajem. Wszystkie wskaźniki dla typów związków muszą mieć takie same wymagania odwzorowania i wyrównania, jak siebie nawzajem. Wskaźniki do innych typów nie muszą mieć tej samej reprezentacji lub wymagań wyrównania .

+0

jednak 6.3.2.3 mówi: 'Wskaźnik do unieważnienia może zostać przekonwertowany na lub ze wskaźnika na dowolny typ niekompletny lub obiektowy . Wskaźnik do dowolnego niekompletnego lub typu obiektu może zostać przekonwertowany na wskaźnik, aby unieważnić iz powrotem; wynik powinien równać się z oryginalnym wskaźnikiem. "Czy to nie ma tu zastosowania? – msam

+0

Dotychczas brzmi to poprawnie, ale czekam na inne opinie, zanim je zaakceptuję. Ponieważ 'void *' jest najogólniejszym typem wskaźnika, 'void **' będzie miał najściślejsze wyrównanie, a zatem rzutowanie na '(CbData **)' będzie czystym ponownym przygotowaniem. Domyślam się, że to jest nielegalne, ale działa nawet na najdziwniejszych architekturach. –

+0

@msam, która mówi o konwersjach typu explicit między wartościami wskaźnika, podczas gdy ja wybijam adres tych wskaźników.Dlatego rzeczy nie są jasne. –

Powiązane problemy