Skocz do zawartości

Kurs STM32L4 – #12 – zewnętrzna pamięć EEPROM (I2C)


Pomocna odpowiedź

@ethanak faktycznie ciekawe, czyli kod z kursu w C++ by nie przeszedł. Coś rodzaju tego:

void mehh(uint8_t *aw, int cnt){
	uint8_t k = 0;
	while(cnt--)
		k = *aw++;
}

void meh(void * aa, int cnt){
	mehh(aa, cnt);
}

W C się skompiluje, bez ostrzeżenia. W C++ wyrzucił błąd:

argument typu "void *" jest niezgodny z parametrem typu "uint8_t *"

 

Link to post
Share on other sites

Bo C++ wymaga bezwzględnej zgodności typów - co przy portowaniu kodu z C na C++ może doprowadzić do traumy. Ostatnio przy portowaniu swojego kodu stwierdziłem, że "const " to powinienem mieć pod jakimś łatwym skrótem klawiszowym, a głupi strtol który miał przesunąć wskaźnik na buforze const char * wymagał jawnego rzutowania na char ** z const char ** (przynajmniej ja nie znalazłem lepszego rozwiązania).

No ale nic dziwnego - to jednak dwa różne języki.

  • Lubię! 1
Link to post
Share on other sites

Długa dyskusja się wywiązała, więc pozwólcie że napiszę kilka słów. Po pierwsze warto zrozumieć czym różni się wartość od wskaźnika - wartość to np. Bajt (uint8_t), int, albo cała struktura. Typ zmiennej określa ile pamięci jest potrzebne do jej przechowywania oraz jak wykonywać operacje na niej. Różne typy mogą zajmować różną ilość pamięci, więc np. Przypisując wartoś zmiennej 32-bitowej do zmiennej 8-bitowej możemy część danych stracić, bo po prostu się nie zmieszczą. Natomiast wskaźnik jest tylko adresem w pamięci, w stm32l4 to zawsze 32-bitowa liczba, a więc każdy typ wskaźnikowy w pamięci wygląda tak samo. Przypisanie wskaźnika do int na wskaźnik do skomplikowanej struktury nie spowoduje żadnej utraty danych, typy mają nas tylko ustrzec przed używaniem wskaźnika do niepoprawnych danych.

To oznacza, że void* jest wskaźnikiem na dowolny typ, po prostu przechowuje jakiś adres w przestrzeni adresowej procesora (nie musi to nawet być RAM). Kompilator bez problemu pozwoli na przypisanie wskaźnika dowolnego typu na void*, bo taka operacja oznacza tylko utratę informacji o typie, nic złego się nie dzieje. Problemem jest natomiast przypisanie void* z powrotem. Takie przypisanie może oznaczać błąd w programie, jeśli przez pomyłkę użyjemy wskaźnika z innym typem.

I tutaj dochodzimy do filozofii, albo raczej decyzji projektowych. Język C na początku wcale nie posiadał kontroli typów, przyjęcie więc że programista wie co robi było więc jak najbardziej sensowne. Nawet po wprowadzeniu kontroli typów, pozostała możliwość przypisywania void* do dowolnego wskaźnika. Natomiast C++ od początku większą wagę przywiązywał do statycznej typizacji, więc konieczne jest użycie jawnego rzutowania.

Czyli w C można napisać:

int x = 5;
int *px = &x;
void *pv = &x;
px = pv;

W C++ ostatnia linijka spowoduje błąd i konieczne będzie jawne rzutowanie, czyli nielubiane:

px = (int*m)pv;

Albo zalecane chociaż dyskusyjnie piękne:

px = static_cast<int*>(pv);

Przykładowe kody były pisane w C, więc jawne rzutowanie nie było konieczne, ważniejsze jest jednak wyjaśnienie, dlaczego używamy void* zamiast uint8_t*. Użytkownik biblioteki powinien mieć możliwość wysyłania i odbierania dowolnych danych, dlatego void* oraz const void* są tutaj o wiele lepszym wyborem. Taki typ jest również używany w standardzie Posix do odczytu i zapisu (read/write). Wywoływana funkcja działa na bajtach, więc wykona sobie jawną lub niejawną konwersję na uint8_t, ale nie powinno to obchodzić użytkownika.

Natomiast dlaczego HAL używa uint8_t* jako parametrów wiedzą pewnie tylko autorzy tej biblioteki. Moja prywatna teoria jest taka, że firmy produkujące świetny hardware, niekoniecznie są ekspertami w tworzeniu oprogramowania (i odwrotnie). Nie można mieć wszystkiego. Ale nie jest to mankament, który uniemożliwiałby korzystanie z zalet dostępnych bibliotek, po prostu taki folklor.

PS. Z góry przepraszam za błędy, post był pisany z telefonu, co nie jest aż takie wygodne jak się wydaje.

  • Lubię! 1
  • Pomogłeś! 1
Link to post
Share on other sites
2 godziny temu, Elvis napisał:

Natomiast dlaczego HAL używa uint8_t* jako parametrów wiedzą pewnie tylko autorzy tej biblioteki. Moja prywatna teoria jest taka, że firmy produkujące świetny hardware, niekoniecznie są ekspertami w tworzeniu oprogramowania (i odwrotnie).

Pięknie 😅

@Elvis dzięki za obszerne wyjaśnienie 🏅

Link to post
Share on other sites
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.