To jest pytanie specyficzne dla C. Staram się zachować wszystko, co możliwe, w granicach jednostki tłumaczeniowej, udostępniając tylko kilka funkcji w .h
pliku. To znaczy, daję static
powiązanie z obiektami na poziomie plików.
Teraz kilka funkcji musi być wywoływanych przez inne moduły, ale nie bezpośrednio. Mój moduł / plik / jednostka tłumacząca subskrybuje inne moduły, przekazując wskaźnik do funkcji. Następnie, po określonym zdarzeniu, wskaźnik jest wywoływany z pewnymi argumentami.
Zastanawiam się więc, jak sprawić, by stało się oczywiste, że te funkcje są wywoływane z jakiejś niejasnej lokalizacji.
- Powinny być
static
lubextern
(i ujawnić je w.h
)? - Czy powinienem zawrzeć podpowiedź w nazwie funkcji?
- Czy wystarczy wstawić komentarz „wywołany przez X”?
c
naming
encapsulation
scope
Vorac
źródło
źródło
Odpowiedzi:
Z punktu widzenia jednostki kompilacji (pliku) jedyne, na co powinieneś zwrócić uwagę, to to, czy funkcja jest dostępna na zewnątrz. Udostępnienie go oznacza, że miał on być wywoływany, i powinieneś działać przy założeniu, że te połączenia się pojawią. Twoja troska o samą funkcję zaczyna się w punkcie wejścia. To, w jaki sposób kontrola się tam dostanie, ma znaczenie tylko dla kodu, który ją powoduje.
Ponieważ powiązanie w każdej implementacji CI znanej jest symboliczne, wszystko, co wywołuje funkcję, musi odnosić się do jej symbolu:
Jeśli przez pomyłkę zadeklarujesz
foo()
sięstatic
, twój program nie będzie łączył się. Jeśli zadeklarujesz, że nie jeststatic
, masz ujawnioną funkcję, która nie jest wywoływana. Pytania dotyczące tego, czy funkcja jest używana, można rozwiązać, zrzucając tabele symboli plików obiektowych lub wyszukując ją w źródłach.źródło
Zdefiniuj „niejasne”.
Metody powinny być udostępniane poprzez dobrze zdefiniowane „interfejsy” i, jak już zasugerował Shivan Dragon, te „interfejsy” są twoimi plikami .h. Jeśli nie podasz innemu programowi „właściwego” pliku nagłówka, wówczas nie będzie mógł wywołać metody.
static
może być OK, o ile nie masz żadnych [klasopodobnych konstrukcji] zawierających dane instancji.extern
oznacza, że tak naprawdę wcale go nie wdrażasz; implementacja jest „pozyskiwana” z innego miejsca podczas procesu łączenia.Absolutnie nie.
Komentarze takie jak te, bez względu na to, jak dobre są ich intencje, są przestarzałe w momencie, gdy je kończysz.
źródło
.h
plik zewnętrzny . Wywołuje stamtąd funkcję i nadaje jej wskaźnik do jednej z własnych funkcji modułu. Później zewnętrzny kod wywołuje cokolwiek, co znajduje się w tym wskaźniku. Tak więc moja funkcja jest wywoływana przez kogoś, kto nie zawiera mojego pliku nagłówka, a raczej jego.extern
słowo kluczowe jest zbędne` .Jeśli funkcje zwrotne są zdefiniowane w twoim module, a użytkownik nigdy nie udostępni własnego, myślę, że możesz użyć symbolu zastępczego podczas fazy inicjalizacji. Symbolem zastępczym jest zazwyczaj taki,
enum
który jest następnie wewnętrznie tłumaczony na odpowiedniąstatic
funkcję.źródło
Nadal bym je tworzył
static
(nie są przeznaczone do łączenia się i wywoływania przez nikogo), i zaznaczam ich cel jako wywołania zwrotne dostarczane do funkcji zewnętrznych w ich imieniu.static
ponieważ próbuję ukryć to, co mogę ukryć, tak bardzo, jak mogę to ukryć.Oznacz je w ich nazwach, ponieważ a) komentarze stają się nieaktualne, i b) w miejscu, w którym dostarczane jest wywołanie zwrotne, staje się oczywiste, że funkcja ta jest przeznaczona do użycia w ten sposób: to zasadniczo oznacza, że jest to czerwona flaga przyjmować adres funkcji, która nie przestrzega konwencji nazewnictwa.
źródło
Modyfikatory zakresu powinny być używane przede wszystkim jako informacja dla kompilatora, a nie jako forma dokumentacji „wystarczająco blisko”. W
static
szczególności użycie kompilatora C sprawia, że funkcja nie nadaje się do użytku spoza modułu, w tym jako wywołanie zwrotne - nie jest to pożądane, nawet jeśli może działać z bieżącym kompilatorem.Oczywiście powinieneś dodać komentarz do kodu, ponieważ widzisz, że jest to potencjalnie myląca sytuacja. Coś niezwykłego lub nieoczekiwanego wymaga odpowiedniego komentarza. Ale, jak stwierdzono w innych odpowiedziach, komentarze mogą być nieprzeczytane lub przestarzałe.
Tak więc jedyną opcją jest nazwa funkcji, aby wskazać, że jest to wywołanie zwrotne. Większość przykładów widziałem użycie
_callback
lub_cb
jako przyrostek lubcb_
jako przedrostek. Użyj długiego formularza, jeśli wywołania zwrotne są nietypowe w kodzie, krótkiego formularza, jeśli są powszechne.źródło