Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Computer Controls
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Programowanie w C i niepewności

OlegTor 12 Sty 2017 10:59 2091 38
  • #1 12 Sty 2017 10:59
    OlegTor
    Poziom 9  

    Witam

    Próbuję nauczyć się programować w C na mikrokontrolery.
    Teraz spotkałem taki kod i mam zagwozdkę:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jak mam rozumieć tą linię z if-em ?

    Pozdrawiam.

    0 29
  • Computer Controls
  • #2 12 Sty 2017 11:57
    marszalek_duck
    Poziom 17  

    Sam if w tym wypadku powinien sprawdzić czy wartość jest różna od NULL ("nic nie zostało przypisane").

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Co do samego przypisania
    Kod: c
    Zaloguj się, aby zobaczyć kod


    To wydaje mi się ze jest ono źle zrobione (tak na szybko sprawdzałem w c online), no chyba ze pominąłeś jakieś linijki pomiędzy o których nie wiem :)

    0
  • Computer Controls
  • #3 12 Sty 2017 12:55
    OlegTor
    Poziom 9  

    To jakiś długi kod, więc wyjąłem z niego interesujące mnie zagadnienie ;)

    Czy można tak to napisać?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    i będzie miało te samo znaczenie?

    PS: pytam, bo nie zabardzo rozumiem te wskaźniki, itp

    0
  • Pomocny post
    #4 12 Sty 2017 13:15
    marszalek_duck
    Poziom 17  

    Tak.

    Przy czym jeżeli mieli byśmy być precyzyjni to zamiast zmiennej "xx" też trzeba by było coś podstawić, np:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Ale to już czepialstwo :lol:


    Przy czym w takim wypadku warunek if zawsze będzie spełniony. Ponieważ te sześć int'ów zostało "stworzone", więc nie wystąpi wartość NULL chociaż sama tablica będzie wskazywać na jakieś "śmieci" (dziwne liczby).

    Tutaj masz przykłady:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Wynikiem będzie oczywiście 5

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Tutaj nie będzie NULL, ale wynikiem będzie jakaś dziwna liczba np. 32767

    0
  • #5 12 Sty 2017 21:48
    OlegTor
    Poziom 9  

    Czyli w tym przypadku:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Gdy do tablicy bufora wpiszemy jakąkolwiek wartość to "if" będzie spełniony. Ale gdy bufor wyzerujemy to nadal będzie warunek spełniony?

    0
  • #6 13 Sty 2017 08:51
    Sparrowhawk
    Poziom 21  

    Nie. W tym przypadku to jest w ogóle UB. bufor to wskaźnik. I jego wartość nie ma nic wspólnego z wartością elementu na który wskazuje.

    Dopiero to ma sens:

    Kod: c
    Zaloguj się, aby zobaczyć kod
    Polecam poczytać: WIKIBOOKS: C/Wskaźniki

    0
  • #7 13 Sty 2017 12:30
    OlegTor
    Poziom 9  

    1. Czyli, żeby nie spełnić warunku wystarczy napisać: bufor=NULL ?

    2. Jak to jest w przypadku przekazywania ?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Czy to jest poprawne ?

    0
  • Pomocny post
    #8 13 Sty 2017 13:21
    marszalek_duck
    Poziom 17  

    1. Tak, jak przypiszesz null, lub nic ne przypiszesz do wskaźnika w trakcie jego życia to if nie przejdzie.

    2. Tak, wynikiem będzie 33. Chociaż przekazanie powinno być inne, w przeciwnym wypadku dostaniesz warningi:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Może się to na pierwszy rzut oka wydawać dziwne, ale jeżeli się troszkę nad tym zastanowisz to ma sens. W pierwszym przypadku wskaźnik będzie wskazywał na pierwszy element tablicy, a w drugim też na pierwszy :)
    Przypadek drugi możesz potraktować jako "formę skróconą" przypadku pierwszego :) Takie ułatwienie dla tablic.

    Równie dobrze możesz zrobić też tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Czy teraz w wyniku będzie 33? NIE. A to dlatego że wskaźnik zaczyna się od elementu 1 oryginalnej tablicy. Dlatego element 5 bufora to tak naprawdę adres elementu 6 wyjściowej tablicy.

    0
  • #9 13 Sty 2017 14:25
    OlegTor
    Poziom 9  

    1. Jak w taki sposób czytać wewnątrz tej funkcji, żeby lokalnie komórka [1] tablicy była globalną [0] ? (czyli odwrotnie niż powyżej)

    2. Czy taki kod będzie miał to samo znaczenie ?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    co
    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #10 13 Sty 2017 14:50
    marszalek_duck
    Poziom 17  

    1. Mógł byś zrobić coś takiego (nie polecam):

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jest to jednak BŁĄD! W tym momencie nie bardzo wiadomo na co wskazuje adres zerowego elementu wskaźnika bufor, może to być jakaś inna zmienna, śmieci itp.

    Tutaj od razu coś wytłumaczę. Wykorzystałem taki fragment:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Na co będzie wskazywał wskaźnik adres? Na element [1] tablicy. Tablicę możesz wyobrazić sobie (w uproszczeniu) jako ustawione w "szeregu" bloki pamięci. Wskaźnik adres na początku wskazuje na zerowy blok ale możemy go przesunąć w jedną lub drugą stronę.

    Więc można zrobić coś takiego:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Przesuwamy się cały czas "do przodu" tablicy.

    Widzę też błąd logiczny:
    Cytat:
    1. Jak w taki sposób czytać wewnątrz tej funkcji, żeby lokalnie komórka [1] tablicy była globalną [0] ? (czyli odwrotnie niż powyżej)

    Nie ma tablicy "lokalnej" i "globalnej" w tym wypadku. Po prostu raz korzystasz z niej "normalnie" (nie pamiętam jak to się nazywa), a wewnątrz Funkcja za pomocą wskaźnika. Ale odczytujesz i zapisujesz tak naprawdę w jednej.

    2. Tak, taki zapis będzie działał i jest nawet bardziej sensowny :)

    0
  • #11 14 Sty 2017 23:07
    OlegTor
    Poziom 9  

    Jeśli wykorzystujemy wskaźnik w przerwaniu to musimy nadać mu volatile ?

    0
  • #12 15 Sty 2017 18:42
    marszalek_duck
    Poziom 17  

    Powinieneś użyć volatile, ale tutaj trzeba trochę uważać żeby się nie pogubić.

    Przykładowo mamy jakąś zmienną która musi być volatile bo używamy jej w przerwaniu lub coś w tym stylu.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Wskaźnik do takiej zmienne będzie wyglądać tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    W tym wypadku jest to wskaźnik do zmiennej volatile. Ale sam wskaźnik volatile nie jest i o ile dobre rozumie (i pamiętam) te mechanizmy to być nie musi. Choć przyznam że lepiej by było aby ktoś z forum jeszcze się na ten temat wypowiedział i to potwierdził lub nie.
    Wiele oczywiście zależy od tego co tworzysz, ale jeżeli chcesz po prostu operować na jakiejś zmiennej poprzez wskaźnik we wnętrzu przerwania to ta opcja jest najlepsza.

    Jednakże, jeżeli przestawisz volatile to sytuacja się zmienia:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Dużo ciekawych informacji na ten temat możesz znaleźć w tym artykule:
    http://blog.regehr.org/archives/28

    Jest tam pokazany też ciekawy trik aby się nie pogubić:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Oczywiście równie dobrze może to być uint8_t :)

    0
  • #13 16 Sty 2017 18:28
    OlegTor
    Poziom 9  

    Dlaczego gdy mam:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    pojawia się w linii wywoływania funkcji: passing argument 1 of 'funkcja' discards qualifiers from pointer target type
    ?

    0
  • Pomocny post
    #14 16 Sty 2017 18:54
    marszalek_duck
    Poziom 17  

    Ponieważ powinno być:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Tak jak wspominałem wcześniej, wskaźnik musi być do odpowiedniego typu.
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Przy czym samo volatile nie jest typem, to specjalna informacja do kompilatora że ma tą konkretną zmienną potraktować inaczej (dokładnie to nie stosować optymalizacji).

    Aby ci to lepiej zobrazować pozwolę sobie zamienić słówko volatile na specjalny. Zerknij teraz co się stało:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Funkcja "oczekiwała" że dostanie wskaźnik do zwykły uint8_t ty jednak przekazałeś jej specjalny uint8_t :D


    I tutaj teraz pojawia się drugi ważny problem (to częsty błąd wśród początkujących). Jest nim czas "życia zmiennych". W swoim programie zastosowałeś dwa wskaźniki bufor

    Kod: c
    Zaloguj się, aby zobaczyć kod


    I kolejny raz postaram się o zobrazowanie tego. Ty jako człowiek widzisz program tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Ale komputer "widzi" ten sam program raczej tak:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Parametry funkcji (czyli tak jak w twoim przypadku) też są zmiennymi lokalnymi. Czyli jeżeli mają taką samą nazwę to zasłaniają te globalne.

    0
  • #15 16 Sty 2017 19:32
    OlegTor
    Poziom 9  

    Dzięki za tak dokładną pomoc. Zajmuję się programowaniem amatorsko, ale coraz bardziej mnie to wciąga :p

    0
  • #16 16 Sty 2017 19:35
    marszalek_duck
    Poziom 17  

    Miło mi :) polecam się na przyszłość.

    1
  • #17 18 Sty 2017 12:07
    OlegTor
    Poziom 9  

    Jak rozumieć ten zapis dla wskaźnika?

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #18 18 Sty 2017 12:26
    Sparrowhawk
    Poziom 21  

    Wskaźnik na stałą typu uint8_t.

    0
  • #19 18 Sty 2017 17:26
    OlegTor
    Poziom 9  

    Też tak myślałem, ale znalazłem taki fragment:

    Kod: c
    Zaloguj się, aby zobaczyć kod
    Nie za bardzo rozumiem tą linijkę, ale ten bufor to:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    więc jak można ustawić pod wskaźnik na zmienną const tablicę do której zapisuje się zmienne.

    0
  • #20 18 Sty 2017 18:11
    marszalek_duck
    Poziom 17  

    Po pierwsze jest to kod c++ a nie c.
    Odpowiednik w c:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    To co tutaj zachodzi to tak zwane rzutowanie. Umożliwia ono zmianę jednego typu na drugi (o ile jest to możliwe).
    Linijce nr. 1 zachodzi właśnie rzutowanie wskaźnika int do wskaźnika const int.

    W linijce nr. 2 przykładowe użycie wartości z tablicy.

    Jak się już sam domyśliłeś w linijce nr. 3 dojdzie do błędu. Wskaźnik wskazuje na typ const int który jest read_only. Więc nie można dokonać zmiany wartości.
    Czasem stosuje się takie rozwiązania (można to w dużym uproszczeniu nazwać getterem). Można dzięki temu zablokować możliwość zmiany wartości. Wyobraź sobie że masz zestaw zmiennych dzięki którym możesz sprawdzić stan portu mikrokontrolera, ale nie powinieneś mieć możliwosci jego zmiany (albo jest taka możliwość ale poprzez inny zestaw zmiennych).

    Gdybyś dodał trochę więcej kodu to może mógłbym złapać jakiś kontekst i coś na ten temat opowiedzieć.

    0
  • #21 21 Sty 2017 22:04
    OlegTor
    Poziom 9  

    Jak to jest z rzutowaniem ?

    Jeśli mam zmienną uint8_t to jak ją w kodzie zmienić i zapisać do zmiennej int8_t ?
    Żeby np. pobrać w postaci uint8_t i wyświetlić w int8_t.

    0
  • #22 21 Sty 2017 22:51
    marszalek_duck
    Poziom 17  

    W takim wypadku nie trzeba stosować rzutowania.
    Robisz to po prostu tak jak przypisanie:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Niestety tutaj mogą wystąpić problemy. Typ uint8_t mieści wartości od 0 do 255, int8_t od -127 do 127. Jeżeli zrobisz takie że w zmiennej a będzie więcej niż mieści b (int8_t) wartość się "przekręci" (tutaj musiał byś zerknąć na operacje binarne).

    Rzutowanie sprowadza się (w uproszczeniu) do tego że kompilator ma pewne obiekcje podczas przypisywania jednego typu do drugiego. Ale ty wiesz lepiej od kompilatora ze nic złego się nie stanie. Coś w stylu "stary, wiem co robię".

    0
  • #23 21 Sty 2017 23:02
    OlegTor
    Poziom 9  

    Chodzi mi o to, że jeżeli np. pobieram bajt z jakiegoś czujnika, transmisją która pobiera ją w postaci uint8_t, a wiem że czujnik wystawia ją jako int8_t. Jak ją wtedy wyświetlić w postaci int8_t ?

    0
  • #24 21 Sty 2017 23:18
    marszalek_duck
    Poziom 17  

    Tu się teraz rodzi pytanie co według ciebie znaczy "wyświetlić"? Masz jakiś wyświetlacz lub serial, czy może chcesz operować na tej wartości jakoś?

    0
  • #25 21 Sty 2017 23:31
    OlegTor
    Poziom 9  

    Na razie chcę ją przesłać przez "serial". Potem wykorzystywać do obliczeń ale w formie int8_t.

    0
  • #26 21 Sty 2017 23:56
    marszalek_duck
    Poziom 17  

    Wydaje mi się że przez serial wysyłasz bajt (np. char lub uit8_t właśnie) więc nie powinno być żadnego problemu pod tym względem. Do obliczeń możesz wykorzystać int (zależy co będziesz robił ale z reguły dużo wygodniejszy) lub float, jeżeli potrzebujesz zmiennoprzecinkowe (na avr float jest bardzo ciężki, są triki które pozwalają na jego ominięcie, ale to już jak będziesz te obliczenia robił).

    Ewentualnie pokaż jak zaimplementowałeś funkcję do wysyłania po serial, może tam leży problem :)

    0
  • #27 22 Sty 2017 00:10
    OlegTor
    Poziom 9  

    Akurat C testuje na STM32 :)
    Napisałem funkcję do czytywania z czujnika który wystawia w swoim rejestrze int16_t, ale u mnie pobierana jest w postaci 2 bajtów uint8_t. Chcę ją przesłać do PC i wyświetlić jako int16_t.

    0
  • #28 22 Sty 2017 01:04
    marszalek_duck
    Poziom 17  

    Aaaaa, no to wiele tłumaczy :)

    Musisz zastosować przesunięcie bitowego. Twoja 16 bitowa wartość jest zapisana w dwóch rejestrach 8 bitowych. Czyli została podzielona na młodszy i starszy bajt.

    Gdybyś zrobił normalne przypisanie:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    To binarnie wyszło by ci coś takiego:
    0000000011111111

    Te jedynki to naszą wartość 255. Problem w tym że teraz jeżeli zrobimy przypisanie kolejnego 8 bitowego rejestru to on nadpisze naszą poprzednią wartość.
    Należy to rozwiązać za pomocą operacji binarnych.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Symbol "<<" jest przesunięciem bitowym. Przesunie on rejestrH o osiem bitów w zmiennej doWysłania, to spowoduje że dostaniemy wartość:
    1111111100000000
    Zamiast (tak jak na początku):
    0000000011111111
    za pomocą operacji OR (symbol "|") dołączymy zmienną rejestrL. Z racji tego że jej nie przesuwamy, to wyląduje on w dolnym bajcie zmiennej doWyslania. I w ten sposób dostajemy jedną zmienną 16 bitową z dwóch 8 bitowych.

    Tak ja bym to zrobił na AVR, na pewno zadziałą też u ciebie. Możliwe że gdzieś w bibliotekach dostarczanych do STM są już do tego gotowe funkcje.
    Warto żebyś zapoznał się z operacjami na bitach, często przydają się w mikro-kontrolerach.

    0
  • #29 22 Sty 2017 11:41
    OlegTor
    Poziom 9  

    Tak zrobiłem, tylko że niestety wyświetla mi w zakresie 0 .. 65535, a ja chcę zobaczyć taką jaką pokazuje czujnik czyli -32768 .. 32767.

    0
  • #30 22 Sty 2017 12:35
    marszalek_duck
    Poziom 17  

    Przyznam się że nie wiem, nie miałem jeszcze z czymś takim problemu. A nic mi nie przychodzi do głowy. Podaj co to za czujnik (model itp), postaram się coś na ten temat wygrzebać.



    Moderowany przez dondu:

    Temat odblokowany na prośbę:

    OlegTor napisał:
    Temat pozwala na znajdowanie odpowiedzi wielu użytkownikom mających pytania.

    0