Jak poprawnie sprawdzić czy wskaźnik do funkcji nie jest NULL'em.

0

Cześć,
Zacząłem doceniać możliwości callback'ów w języku C. Mam taką funkcję inicjalizującą moduł komunikacyjny. Instrukcja warunkowa sprawdza czy nie podajemy pustego wskaźnika do funkcji.

int8_t comm_mgr_init(int8_t (*dump_buff_fptr)(char *, uint16_t))
{  
  if(dump_buff_fptr != 0)
  {
    return -1;
  }
  comm_struct.dump_buff_fptr = dump_buff_fptr;
  return 0;
}

To rozwiązanie nie zadziała zawsze. W przypadku gdy wywołamy funkcję comm_mgr_init w sposób jak poniżej inicjalizacja się zakończy powodzeniem, lecz niestety to będzie wskaźnik w miejsce w którym nie ma żadnej funkcji.

int8_t* ptr;
comm_mgr_init(ptr);

Czy w C można jakoś sprawdzić który wskaźnik jest wskaźnikiem do funkcji? Jakieś makra etc.?

0

To co robisz to UB. Korzystasz z niezainicjowanego wskaźnika. Taki wskaźnik zawiera śmieci. Dlatego sprawdzanie nie działa. Zrób tak;

int8_t* ptr = NULL;
comm_mgr_init(ptr);

Wtedy zadziała.

0

W tym przypadku ptr ma losową wartość ze stosu, więc porównanie do NULL nic nie da.
Myślę, że można by zapytać system, czy pod tym adresem znajduje się kod. Ale nie jest to rozwiązanie idealne, bo nawet jeśli jest tam kod, to nie koniecznie musi to być początek funkcji.
Najlepiej było by chyba zrobić coś w takim stylu:

int8_t* ptr = NULL;

;)

0

Niestety systemu nie mogę się zapytać to jest kod na uC. Funkcja comm_mgr_init to interfejs z którego będą korzystały wyższe warstwy i inni programiści będą ją wywoływali. Na 99.9% każdy poda wskaźnik do funkcji, ale co jednak gdy ktoś poda niezainicjalizowany wskaźnik?

0

To będzie Undefined Behaviour. Nie masz jak sprawdzić tego bo wartość będzie "śmieciami" z pamięci.

0
int8_t comm_mgr_init(int8_t (*dump_buff_fptr)(char *, uint16_t))

Dla lepszej czytelności warto zdefiniować osobny typ dla parametru:

typedef int8_t (*dump_buff_proc_t)(char *, uint16_t);

int8_t comm_mgr_init(dump_buff_proc_t dump_buff_proc)
0

W języku C nie masz możliwości upewnienia się czy dany adres prowadzi do funkcji. Masz jedynie możliwość zainicjowania w sposób prawidłowy wskaźników. Mając pewność że dane statyczne inicjowane przed funkcją main() są domyślnie inicjowane wartością 0 (co jest elementem standardu), wykorzystaj ten fakt jeszcze przed uruchomieniem przerwań MCU (jak się domyślam).Inicjuj wskaźnik NULL'em i tyle :-)
Innym pytaniem jest to, czy zmiany wskaźnika będą wykonywane atomowo (czyli nawet dla prostych MCU np. nie będę zakłócane przez przerwanie) oraz to czy naprawdę potrzebujesz dynamicznego rejestrowania/wyrejestrowania wskaźnika na funkcję. Często taka rejestracja wykonywana jest tylko raz. Wtedy dobrym rozwiązaniem jest makro rejestrujące taki wskaźnik.

0

O takim makrze mówisz?
#define DECLARE_DUMP_FUNC(debug_write, data, size) int8_t debug_write(char *data, uint16_t size)

1 użytkowników online, w tym zalogowanych: 0, gości: 1