programowanieEmbedded C developer

Opisz, jak są realizowane i działają funkcje zwrotne (callback functions) w języku C. Jak poprawnie deklarować i używać takich funkcji podczas opracowywania bibliotek lub interakcji z API?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Funkcje zwrotne (callback) to funkcje, których adres jest przekazywany jako argument innej funkcji. Pozwala to na realizację obsługi zdarzeń, algorytmów użytkownika i wtyczek.

Deklaracja funkcji callback:

  1. Opisuje odpowiedni typ wskaźnika na funkcję:
typedef void (*callback_func_t)(int);
  1. Przekazanie funkcji obsługującej:
void process(callback_func_t cb) { // ... cb(42); // wywołanie callback } void handler(int n) { printf("Przetworzone liczba: %d\n", n); } int main() { process(handler); return 0; }

Wskazówki:

  • Trzymaj się jawnego typedef dla typów wskaźników, kod stanie się bardziej czytelny.
  • Upewnij się, że sygnatura funkcji callback jest zgodna z oczekiwaną.
  • Unikaj przesyłania lokalnych, nieinicjowanych lub zwolnionych funkcji.

Pytanie podchwytliwe

Czy można przekazać funkcję o niezgodnej sygnaturze jako callback?

Częsty błędny odpowiedź: „Tak, C pozwoli, jeśli zadeklarujesz jawne rzutowanie typu”.

Poprawna odpowiedź: Chociaż formalne rzutowanie jest możliwe, wywołanie takiej funkcji prowadzi do niezdefiniowanego zachowania — parametry mogą otrzymywać nieprawidłowe wartości, stos ulegnie uszkodzeniu.

Przykład niebezpieczeństwa:

typedef void (*cb_t)(int); void wrong_cb(double d) { printf("%f\n", d); } void call(cb_t f) { f(123); } int main() { call((cb_t)wrong_cb); } // NIEBEZPIECZNE: sygnatury różnią się

Przykłady rzeczywistych błędów z powodu nieznajomości zagadnień


Historia

W jednym z projektów wbudowanych funkcja sortująca otrzymała jako funkcję porównującą wskaźnik na funkcję o zbyt wąskiej sygnaturze. Doprowadziło to do błędów sortowania i uszkodzenia pamięci z powodu nieprawidłowego przekazywania parametrów.

Historia

W bibliotece silnika graficznego zrealizowano mechanizm zdarzeń oparty na callbackach, ale część callbacków przypadkowo odwoływała się do lokalnych funkcji z już zwolnionych bibliotek dynamicznych, co powodowało awarie w przypadku napotkania nieprawidłowych adresów.

Historia

Podczas opracowywania systemu wieloplatformowego autor niewłaściwie określił konwencję wywołania dla funkcji callback. Nie ujawniało się to w jednym systemie operacyjnym, ale prowadziło do awarii programu w innym przy wywołaniu callbacków z biblioteki C.