Chciałem zadać pytanie do konkretnego kawałka kodu z pełnym przekonaniem, że teorię to ja już pojąłem, a mimo wszystko coś nie pasuje.
I tak opisując w miarę dokładnie to z czym się zmagałem, pod sam koniec, na chwilkę przed kliknięciem
Wyślij otrzymałem odpowiedź, jak grom z jasnego nieba, kończąc opisywać problem z którym nie mogłem sobie poradzić.
Może gdyby komuś, kiedyś trafił się podobny problem ze zrozumieniem tych zagadnień w konkretnym przykładzie... wrzucam tego posta, jak krok po kroku próbowałem to opisać, żeby ktoś mi pomógł, aż w końcu z BlueBookiem doszedłem do rozwiązania.
tak to się zaczęło:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Czytając artykuł
Obsługa klawiszy - drgania styków CD...2, napotkałem taki problem, którego nie potrafię sam przejść.
Dotyczy tego programu.
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Zmieniłem w nim 22 linię na coś takiego, tak w ramach testów na:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
i po tej zmianie nie działa już ten program tak jak powinien, bo nie można zmieniać stanu diody na przeciwny po tej modyfikacji.
Zacząłem analizować poszczególne przypadki po kolei, od początku robiąc to w następujący sposób:
--- rozpoczęcie programu - Pierwsze wejście - do pętli while(1) ---1) sytuacja
Klawisz KEY1 --- NIE wciśniętyif(!
00000000 && !(
1xxxxxxx &
10000000) )
if( 1 && ! (
10000000) )
if( 1 && 0 )
if( 0 )
W instrukcji FAŁSZ, więc przechodzę do else if()else if(
00000000 && (
1xxxxxxx &
10000000) )
else if(
00000000 &&
10000000 )
else if( 0 )
W instrukcji FAŁSZ, więc zmienna key_lock = 0 nadal równa się zero, dopóki nie wcisnę przycisku, to program będzie tak latał w pętli while(1) BEZ ZMIAN ---->
--- kolejne wejścia - do pętli while(1) ------ rozpoczęcie programu - Pierwsze wejście - do pętli while(1) ---2) sytuacja
Klawisz KEY1 --- Wciśniętyif( !
00000000 && !(
0xxxxxxx &
10000000) )
if( 1 && !(
00000000) )
if( 1 && 1)
if( 1 ) key_lock=1;
W instrukcji PRAWDA, więc key_lock = 1, a to co dalej czyli elese if() już się nie wykona...... i gdy tak będę trzymał ten klawisz wciśnięty w tej sytuacji i nie będę go puszczał to program wejdzie po raz kolejny do pętli while(1) ----> --- kolejne wejścia - do pętli while(1) ---if(!
00000001 && !(
0xxxxxxx &
10000000) )
if( 0 && ! (
00000000) )
if( 0 && 1 )
if( 0 )
W instrukcji FAŁSZ, więc przechodzę do else if()else if(
00000001 && (
0xxxxxxx &
10000000) )
else if(
00000001 &&
00000000 )
else if( 0 )
W instrukcji FAŁSZ, więc program, znów wskakuje do pętli while(1), a ja nie puszczam klawisza, tak jak bym się o niego oparł i zasnął... klawisz jest cały czas wciśnięty, więc program przechodzi wszystkie warunki tak, jak w powyżej przedstawionej kolejności i nic się nie zmienia, program tak lata i lata "w kółko..."...aż w końcu podczas snu przewracam się na drugi bok i już puszczam ten klawisz...--- kolejne wejścia - do pętli while(1) ---if(!
00000001 && !(
1xxxxxxx &
10000000) )
if( 0 && ! (
10000000) )
if( 0 && 0 )
if( 0 )
W instrukcji FAŁSZ, więc przechodzę do else if()else if(
00000001 && (
1xxxxxxx &
10000000) )
else if(
00000001 &&
10000000 )
else if( 1 )
no w końcu, program doszedł do bloku po else if(1) , który wykona zmianę stanu diody na przeciwny... A zmiana, ta wykona się dzięki temu, że puściłem, ten przycisk.język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
...ale chwila, chwila, zanim jednak dokona się ta zmiana to jest przecież jeszcze jedna instrukcja if() po drodze, w której jest:NegacjaLogiczna Preinkrementacji zmiennej key_lock
i tutaj właśnie zaczynają się dla mnie schody...
wyczytałem w BB:
- 94 str., że cyt.: "Jeśli operator ++ stoi przed zmienną, to najpierw jest ona zwiększana o jeden, a następnie ta już zwiększona wartość brana jest jako wynik tego wyrażenia"
- 107 str., że operatory przedrostkowe:
! i
preinkrementacja są tej samej, wagi, mają ten sam priorytet, a ich łączność jest prawostronna, co oznacz że działanie wykonuje się od strony prawej.
No to po takim zastrzyku wiedzy, siup, myślę sobie tak...key_lock był równy 1, to będzie tak:if(!++key_lock)
if(!++1)
if(!2)
if(0)
key_lock został najpierw zwiększony z wartości = 1, do wartości = 2, następnie został zanegowany negacją logiczną i warunek instrukcji if() jest teraz FAŁSZEM, więc zmiana stanu diody jeszcze się nie wykona...Działa opisany mechanizm na blogu nazwany przez naszego Mistrza:
mikro programowy timer program po raz kolejny wskakuje do pętli while(1) i zwiększa stan zmiennej key_lock aż do wartości jaką może maksymalnie osiągnąć, czyli 255, bo jest typu uint8_t, a jak osiągnie 255 to następnie po zwiększeniu o 1, będzie key_lock wyzerowany, czyli key_lock=0 przyjmie wartość zero.--- kolejne wejścia - do pętli while(1) --- podczas gdy zwiększa się z kolejnymi wejściami wartość zmiennej key_lock
if(!
00000_ _ _ && !(
1xxxxxxx &
10000000) )
w miejscu _ _ _ zwiększają się te watości key_lock przez co zawsze ten pierwszy człon ifa będzie z logicznego punktu widzenia PRAWDĄ, która będzie negowana if( 0 && ! (
10000000) )
...w tej linii widać to pierwsze zero, to jest ta zanegowana PRAWDAif( 0 && 0 )
if( 0 )
W instrukcji FAŁSZ, więc przechodzę do else if()else if(
00000001 && (
1xxxxxxx &
10000000) )
else if(
00000001 &&
10000000 )
else if( 1 )
-----------------------------------------------------------------------------
i w tym miejscu po tak szczegółowym rozpisaniu dochodzę do tego...key_lock = 1
if(!++key_lock)
if(!++1)
if(!2) --------------------- key_lock=2
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
key_lock = 2
if(!++key_lock)
if(!++2)
if(!3) --------------------- key_lock=3
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
key_lock = 3
if(!++key_lock)
if(!++3)
if(!4) --------------------- key_lock=4
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
key_lock = 4
if(!++key_lock)
if(!++5)
if(!2) --------------------- key_lock=5
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
.
.
.
key_lock = 255
if(!++key_lock)
if(!++255)
if(!0) --------------------- key_lock=0
if(
1)
---------------------------------- PRAWDA
mikro programowy timer wykonał swoją robotę
zmieni się stan diody na przeciwny, a następna zmiana jeśli się będzie miała dokonać, to będzie trzeba ponownie przejść taką samą drogę, tzn. wcisnąć klawisz, następnie puścić...
mikro programowy timer wykona swoją robotę
(ZROBI TO BARDZO SZYBCIUTEŃKO, ja tego nie zauważę nawet... ale stan przejściowy w którym akurat mogą wystąpić drgania styków minie... i nie będzie żadnych problemów z niespodziewanymi zmianami stanu diody).
No i się cieszę, bo podany przykład działa tak jak powinien
-----------------------------------------------------------------------------------------------------------------------------
Ale jak sobie chciałbym przeanalizować to samo z tą małą zmianą, którą jak już wspomniałem, zadałem sobie tak dla testów.
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
w 22 linijce...
to sięgając ponownie do książki:
- 94 str. cyt.: "jeśli operator stoi za zmienną, to najpierw brana jest pod uwagę stara wartość tej zmiennej i ona będzie wynikiem tego wyrażenia. Następnie, po operacji, gdy wynik został już pobrany do obliczeń, wartość ta jest zwiększana o jeden"
- 107 str. w tabelce priorytetów operatorów
postinkrementacja ma większy priorytet niż
! negacja logiczna.
Po tym co przeczytałem, ja to widzę tak... /może? tu gdzieś leży błąd w moim rozumowaniu/ że skoro postinkrementacja ma większy priorytet niż negacja logiczna to operacja postinkrementacji na zmiennej key_lock jest wykonywana najpierw, a potem już w następnej kolejności jest robiona negacja logiczna - czyli myślę/wydaje mi się że jest to to samo co w przypadku z preinkrementacją, z tą różnicą, że w pierwszym przypadku gdy key_lock = 1, negacja zostanie wykonana na wartości 1, a nie wartości 2:
key_lock = 1
if(!key_lock++)
if(!1++) --------------------zgodnie z priorytetem postinkrementacji przekazuję dalej key_lock=1
if(!1) --------------------- wynik w tym przypadku został już pobrany do obliczeń, zwiększam key_lock o jeden, więc key_lock=2, (zwiększenie nie wpłynęło na wartość wyrażenia, na którym wykona się negacja)
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
key_lock = 2
if(!key_lock++)
if(!2++) --------------------zgodnie z priorytetem postinkrementacji przekazuję dalej key_lock=2
if(!2) --------------------- wynik w tym przypadku został już pobrany do obliczeń, zwiększam key_lock o jeden, więc key_lock=3, (zwiększenie nie wpłynęło na wartość wyrażenia, na którym wykona się negacja)
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
key_lock = 3
if(!key_lock++)
if(!3++) --------------------zgodnie z priorytetem postinkrementacji przekazuję dalej key_lock=3
if(!3) --------------------- wynik w tym przypadku został już pobrany do obliczeń, zwiększam key_lock o jeden, więc key_lock=4, (zwiększenie nie wpłynęło na wartość wyrażenia, na którym wykona się negacja)
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
key_lock = 4
if(!key_lock++)
if(!4++) --------------------zgodnie z priorytetem postinkrementacji przekazuję dalej key_lock=4
if(!4) --------------------- wynik w tym przypadku został już pobrany do obliczeń, zwiększam key_lock o jeden, więc key_lock=5, (zwiększenie nie wpłynęło na wartość wyrażenia, na którym wykona się negacja)
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
.
.
.
key_lock = 255
if(!key_lock++)
if(!255++) --------------------zgodnie z priorytetem postinkrementacji przekazuję dalej key_lock=255
if(!255) --------------------- wynik w tym przypadku został już pobrany do obliczeń, zwiększam key_lock o jeden, więc key_lock= 0, (zwiększenie nie wpłynęło na wartość wyrażenia, na którym wykona się negacja)
if(0) --------------------- FAŁSZ zmiana stanu diody się jeszcze teraz nie dokona
*key_lock = 0
if(!key_lock++)
if(!0++) --------------------zgodnie z priorytetem postinkrementacji przekazuję dalej key_lock=0
if(!0) --------------------- wynik w tym przypadku został już pobrany do obliczeń, zwiększam key_lock o jeden, więc key_lock= 1, (zwiększenie nie wpłynęło na wartość wyrażenia, na którym wykona się negacja)
if(
1)
---------------------------------- PRAWDA <------------------------ ale tu nigdy program nie dojdzie, w związku z czym nie zmieni NIGDY stanu diody na przeciwny, bo krok wcześniej key_lock w wyniku operacji postinkrementacji osiągnie zero, i jedyne co będzie można programowi nakazać żeby się nie nudził... to podczas ponownego wciśnięcia przycisku i puszczenia go, danie programowi zadania, żeby sobie zwiększał wartość zmiennej key_lock operacją postinkrementacji od 1 przez kolejne liczby całkowite do 252, 253, 254, 255, 0 ... co jak widać nie przyniesie żadnych zmian, przez tą różnicę, (której nie dostrzegałem kiedy zacząłem opisywać ten mój problem, żeby otrzymać pomoc na forum
) pomiędzy -PRE -POST -Inkrementacjami.
Przełom nadszedł dopiero w miejscu oznaczonym
*, a więc prawie na sam koniec, kiedy już myślami byłem na klikaniu
Wyślij i czekaniu aż mi ktoś odpowie