Jak sprawić, by oczywista była dostępność funkcji z zewnątrz?

9

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 .hpliku. To znaczy, daję staticpowią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ć staticlub extern(i ujawnić je w .h)?
  • Czy powinienem zawrzeć podpowiedź w nazwie funkcji?
  • Czy wystarczy wstawić komentarz „wywołany przez X”?
Vorac
źródło
1
To doskonałe pytanie. Moje rozwiązanie (z którego wcale nie jestem zbyt szczęśliwy, dlatego umieszczam je tylko w komentarzu) polega na tworzeniu wielu plików nagłówkowych, rozsądnie nazwanych i grupujących funkcje w zakresie, który chcę, aby miały. Do stworzonej przeze mnie biblioteki AStar mam AStar.h, AStar_private.h, AStar_packagePrivate.h itp.
Shivan Dragon

Odpowiedzi:

2

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:

foo();  /* Direct */

some_function_pointer_t funcs[] = { &foo, &bar, &baz };  /* Indirect */

Jeśli przez pomyłkę zadeklarujesz foo()się static, twój program nie będzie łączył się. Jeśli zadeklarujesz, że nie jest static, 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.

Blrfl
źródło
1

Zastanawiam się więc, jak sprawić, by stało się oczywiste, że funkcje te są wywoływane z jakiejś niejasnej lokalizacji.

Zdefiniuj „niejasne”.
Metody powinny być udostępniane poprzez dobrze zdefiniowane „interfejsy” i, jak już zasugerował Shivan Dragon, te „interfejsy” 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.

Czy powinny być statyczne czy zewnętrzne (i eksponować je w .h)?

static może być OK, o ile nie masz żadnych [klasopodobnych konstrukcji] zawierających dane instancji.
externoznacza, że tak naprawdę wcale go nie wdrażasz; implementacja jest „pozyskiwana” z innego miejsca podczas procesu łączenia.

Czy powinienem zawrzeć podpowiedź w nazwie funkcji?

Czy wystarczy wstawić komentarz „wywołany przez X”?

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.

Phill W.
źródło
Zwracając się do pierwszego punktu, funkcje są wywoływane w następujący sposób. Mój komponent zawiera .hplik 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.
Vorac
1
Jeśli chodzi o drugi punkt, to o ile rozumiem, obiekt zdefiniowany w zakresie pliku ma domyślnie zewnętrzny link; dlatego externsłowo kluczowe jest zbędne` .
Vorac,
0

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, enumktóry jest następnie wewnętrznie tłumaczony na odpowiednią staticfunkcję.

lorcap
źródło
0

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.

Sebastian Redl
źródło
0

Modyfikatory zakresu powinny być używane przede wszystkim jako informacja dla kompilatora, a nie jako forma dokumentacji „wystarczająco blisko”. W staticszczegó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 _callbacklub _cbjako przyrostek lub cb_jako przedrostek. Użyj długiego formularza, jeśli wywołania zwrotne są nietypowe w kodzie, krótkiego formularza, jeśli są powszechne.

Jonathan Giddy
źródło