Elektronika - baza wiedzy

Cześć 8 kursu C/C++


8. Operacje logiczne

O ile w przypadku operacji artymetycznych wynikiem mogła być dowolna liczba (oczywiście z określonego zakresu), to wynikiem operacji logicznej jest jeden z dwóch możliwych stanów - prawda lub fałsz . W języku C za fałsz uznaje się liczbę zero, natomiast wszystkie pozostałe są uznawane za prawdę . Wynikiem takiego traktowania stanów logicznych jest możliwość używania kompaktowych wersji porównań logicznych, co zobaczymy w następnej części tego punktu.


8.1. Porównania


W tym podpunkcie przedstawię je tylko, natomiast przykłady ich wykorzystania zostaną zaprezentowane w następnym podpunkcie. W języku C mamy następujące operatory porównania:


C
Pascal
Opis

>
>
większe niż

<
<
mniejsze niż

>=
>=
większe lub równe

<=
<=
mniejsze lub równe

==
=
równe (zwróć uwagę na podwójny znak równości)

!=
<>
nie równe



8.2. Instrukcja if

Instrukcja ta jest istotnym elementem każdego programu, ponieważ pozwala ona na modyfikację sposobu, w jaki działa program w zależności od wartości danych. W języku C, podobnie jak w Pascalu, ma ona następującą składnię:

if(wyrażenie) wyrażenie1 else wyrażenie2

Jeśli wyrażenie w nawiasie ma wartość logiczną prawda to zostanie wykonane wyrażenie1, w przeciwnym wypadku zostanie wykonane wyrażenie2. Przykładowo:

if( a > 10 ) printf("Zmienna a jest większa od dziesięciu !"); else printf("Zmienna a jest mniejsza lub równa dziesięć !");

Zauważ, że zarówno wyrażenie po if , jak i wyrażenie po else jest zakończone średnikiem. Uwagę tą kieruję szczególnie do osób znających Pascala, w którym średnik stawia dopiero na samym końcu. Oczywiście, tak jak w Pascalu, części "else" możesz w ogóle nie używać, jeśli nie jest Ci to akurat potrzebne. Czyli możesz napisać tak:

if( a > 10 ) printf("Zmienna a jest większa od dziesięciu !");

Jeśli chcesz wykonać kilka instrukcji jeśli spełniony jest pewien warunek to musisz je zawrzeć w bloku ograniczonym znakami { i } . Czyli wyglądałoby to następująco:



if( a > 10 ) {

printf("Zmienna a jest wieksza od dziesięciu ! ");

printf("Jest bowiem równa %d.", a);

} else {

printf("Zmienna a jest mniejsza lub równa dziesięć ! ");

if(a != 5) printf("Jednak nie jest równa pieć !");

}

Oczywiście to, jak sformatujesz ten tekst (np. możesz znak rozpoczynający blok wpisań w nowej linii) zależy tylko od Ciebie. Ja jednak preferuję taki sposób, według mnie jest to bardziej czytelne.

Pozostała do omówienia jeszcze jedna rzecz dotycząca instrukcji if , a związana z traktowaniem przez język C wartości logicznych. Zamiast:

if ( a != 0 ) printf("a jest rozne od zera");

możemy napisać:

if( a ) printf("a jest rozne od zera");

i będzie to działało w identyczny sposób. Jak myślisz dlaczego ? Jeśli przeczytałeś uważnie wstęp do operacji logicznych to nie powinieneś mieć większych problemów z odpowiedzią na to pytanie. W pierwszym przypadku mamy do czynienia z porównaniem wartości zmiennej a do zera. Przykładowo, jeśli zmienna a jest równa dziesięć to warunek "a != 0" zwróci prawdę do instrukcji if i zostanie wyświetlony na ekranie tekst. Natomiast co z drugim przypadkiem ? Nie mamy tu do czynienia z żadnym porównaniem, do instrukcji if jest od razu przekazywana wartość zmiennej a, czyli w naszym przypadku dziesięć. Zauważ, nie prawda , nie fałsz , ale liczba dziesięć ! I co się stanie teraz ? Po prostu na ekranie pojawi się tekst. Pamiętasz jak język C traktuje wartości logiczne ? Stanowi fałsz odpowiada liczba zero, natomiast stanowi prawda każda inna wartość. Czyli także liczba dziesięć ! Tak więc liczba ta zostanie potraktowana jako stan prawda i w wyniku tego zostanie wykonana odpowiednia instrukcja (blok instrukcji) - w naszym przypadku zostanie wywołana funkcja printf .

Na zakończenie tego punktu zamieściłem jeszcze przykład często popełnianego błędu (który na dodatek bardzo trudno jest zlokalizować), związanego z właśnie takim traktowaniem stanów logicznych przez język C:

if( a = 0 ) printf("a jest równe zero");
else printf("a jest różne od zera");

Jak myślisz, co zostanie wyświetlone na ekranie, jeśli powiem Ci, że zmienna a jest równa zero ? Jeśli odpowiesz, że będzie to "a jest równe zero" to niestety nie będziesz miał racji. Możesz zapytać: "Ale dlaczego ? Przecież mamy porównanie a do zera i ponieważ a jest równe zero, to powinien wyświetlić się pierwszy napis.". Miałbyś rację, jeśli naprawdę byłoby tam porównanie. Jednak przyjrzyj się uważnie - tam nie ma porównania ! Porównanie w języku C to podwójny znak równości, natomiast pojedynczy (tak jak jest w tym przypadku) oznacza przypisanie. Tak więc najpierw zostanie tu przypisana wartość zero do zmiennej a, a następnie (tak jak w poprzednim przykładzie) wartość tej zmiennej zostanie przekazana do instrukcji if , która potraktuje ją jako fałsz (bo zero właśnie to oznacza) i w efekcie wywoła funkcję printf występującą po else .



8.3. Podstawowe operacje logiczne


W podpunkcie tym przedstawię cztery podstawowe operacje logiczne - OR, AND, NOT i XOR. Jeśli wiesz na jakiej zasadzie one działają to możesz przejść do następnego podpunktu. Zero w tabeli odpowiada stanowi fałsz , natomiast jedynka odpowiada stanowi prawda .



Operacja OR (lub)

Wejście
Wyjście

0
0
0

1
0
1

0
1
1

1
1
1



Wynikiem operacji OR jest zero, gdy oba argumenty są równe zero, lub jedynka w przeciwnym wypadku.



Operacja AND (i)

Wejście
Wyjście

0
0
0

1
0
0

0
1
0

1
1
1



Wynikiem operacji AND jest jedynka, gdy oba argumenty są równe jeden, lub zero w przeciwnym wypadku.



Operacja XOR

Wejście
Wyjście

0
0
0

1
0
1

0
1
1

1
1
0



Wynikiem operacji XOR jest jedynka, gdy tylko jeden z argumentów jest równy jeden, lub zero w przeciwnym wypadku.



Operacja NOT

Wejście
Wyjście

0
1

1
0



Wynikiem operacji NOT jest jedynka, gdy argument był równy zero, lub zero, gdy argument był równy jeden.



8.4. Operacje logiczne w języku C


Przedstawione w poprzednim punkcie operacje mają w języku C dwa aspekty - logiczny i arytmetyczny (operacje na bitach). Co prawda drugi z nich należałoby przedstawić już wcześniej, przy okazji omawiania operacji arytmetycznych, jednak zrobię to dopiero w tym punkcie z uwagi na podobieństwo. Najpierw jednak skupmy się na pierwszym aspekcie. Oto jak operacje logiczne zapisujemy w języku C:



Operacja
C
Pascal

OR
||
or

AND
&&
and

NOT
!
not



Ponieważ o wiele łatwiej jest uczyć się na przykładach, podam teraz program, który zilustruje wykorzystanie poznanych operacji logicznych.





#include <stdio.h>



void main(void)

{

int a = 17;



// przykład użycia operacji logicznej OR

if( (a 10) ) {

printf("Zmienna a jest mniejsza od pięciu _lub_ większa od dziesięciu. ");

}



// przyklad użycia operacji logicznej AND

if( (a 10) && (a




Ponieważ początek programu nie wymaga chyba komentarza (jeśli wymaga to cofnij się, proszę, do poprzednich punktów), analizę naszego programu zaczniemy od linijki z pierwszym wystąpieniem instrukcji if .

W naszym przypadku chcemy wykonać jakieś działanie (wyświetlenie tekstu na ekranie), gdy zmienna a jest mniejsza od pięciu lub też większa od dziesięciu. Idealnie do tego celu nadaje się operacja logiczna OR , której używa się, gdy chcemy sprawdzić czy chociaż jeden z podanych warunków jest prawdziwy . Widzimy, że mamy tu dwa porównania - pierwsze (a < 5) , dla zmiennej a równej siedemnaście zwraca fałsz , jednak drugie (a > 10) , zwraca prawdę (bo 17 > 10). Operacja logiczna OR dla takich parametrów zwraca prawdę (zobacz w tabeli przedstawionej powyżej), tak więc zostanie wyświetlony na ekranie odpowiedni tekst. Zapamiętaj więc - jeśli chcesz sprawdzić, czy którykolwiek z warunków jest spełniony, użyj operacji OR.

W sytuacji, gdy wykonanie działania ma zależeć od spełnienia wszystkich warunków, używamy natomiast instrukcji logicznej AND . Pokazane jest to przy okazji następnej instrukcji if . W tym wypadku chcemy wykonać działanie tylko wtedy, gdy zmienna a jest większa od dziesięciu i mniejsza od dwudziestu (czyli zawiera się w określonym przedziale). Pierwszy warunek (a > 10) , dla zmiennej a równej siedemnaście zwraca prawdę , drugi (a < 20) także zwraca prawdę . Patrząc do tabeli widzimy, że w takim przypadku wynikiem operacji AND jest prawda , więc na ekranie zostanie wyświetlony tekst o tym informujący. Zapamiętaj więc - jeśli chcesz wykonanie działania uzależnić od spełnienia wszystkich warunków, użyj operacji AND.

Przejdźmy teraz do omówienia ostatniej, najprostszej operacji logicznej, a mianowicie NOT . Jest ona po prostu negacją (zaprzeczeniem) danego parametru - tzn. że dla parametru prawda zwróci fałsz, natomiast dla parametru fałsz zwróci wartość prawda. Pokazuje to wyraźnie trzecia z instrukcji if w naszym programie. Warunek (a < 10) jest sformułowany tak, że dla zmiennej a równej siedemnaście, zwróci fałsz , czyli normalnie tekst nie zostałby wyświetlony na ekranie. Jednak w naszym przypadku występuje jeszcze negacja, która "zamienia" fałsz na prawdę i w efekcie na ekranie pojawi się odpowiedni napis.



8.5. Operacje na bitach


Pozostało jeszcze do omówienia zastosowanie poznanych operacji logicznych do wykonywania działań na bitach. Do zrozumienia (i wykorzystania w swoich programach) podanych w tym punkcie informacji konieczna będzie znajomość podstaw dwójkowego systemu zapisu liczb. Jeśli nie wiesz co to takiego to sugeruję, żebyś pominął teraz ten punkt i powrócił do niego po zaglądnięciu do książki z matematyki (ja to miałem w 7 lub 8 klasie podstawówki, teraz to chyba będzie w gimnazjum). Najpierw przedstawię operatory języka C stosowane do operacji na bitach:



Operacja
C
Pascal

OR
|
or

AND
&
and

XOR
^
xor

NOT
~
not



Wszystkie przedstawione w tabeli operacje mają taką samą zasadę działania. Pierwsze trzy operują na dwóch argumentach, natomiast ostatnia tylko na jednym. Algorytm działania tych pierwszych wygląda tak:



1. Najpierw zamieniasz oba argumenty na postać binarną.

2. Teraz bierzesz zerowe bity obu argumentów i wykonujesz odpowiednią operację logiczną

3. To, co otrzymałeś zapisujesz w zerowym bicie wyniku.

4. Punkty dwa i trzy wykonujesz kolejno dla pierwszego, drugiego, itd. bitu argumentu.

Natomiast algorytm działania operacji NOT jest dużo prostszy - po prostu neguje ona wszystkie bity argumentu. Czyli w efekcie tam, gdzie były zera, teraz będą jedynki i odwrotnie.

Być może nie zrozumiałeś wszystkiego z powyższego opisu. Jednak nie martw się - wszystko się wyjaśni przy analizie przykładowego programu:





#include <stdio.h>



void main(void)

{

char a=12, b=9;



printf("%d and %d = %d ", a, b, a & b);

printf("%d or %d = %d ", a, b, a | b);

printf("%d xor %d = %d ", a, b, a ^ b);

printf("not %d = %d ", b, ~b);

}


Każde z wywołań funkcji printf prezentuje inny operator. Zacznijmy od operacji AND.

Jak widzisz wykonujemy operację AND na dwóch argumentach - zmiennej a równej dwanaście i zmiennej b równej dziewięć. Po zapisaniu tego w postaci dwójkowej wygląda to następująco:



1100 (12 w systemie dziesiętnym)

AND

1001 (9 w systemie dziesiętnym)

====

1000 (8 w systemie dziesiętnym)

Na podstawie algorytmu działania przedstawionego powyżej pokażę w jaki sposób otrzymaliśmy w efekcie liczbę osiem. Najpierw zamieniamy obie liczby na postać binarną. Dla lepszego zobrazowania zapisałem je jedna nad drugą. Bierzemy teraz zerowy (ten z prawej) bit pierwszej liczby (12) - jest on równy zero. Następnie bierzemy zerowy bit drugiej liczby (9) - jest on równy jeden. Wykonujemy operację AND na tych danych - w efekcie otrzymujemy zero (zobacz w tabeli dla operacji AND), którą to zapisujemy jako zerowy bit wyniku. Teraz to samo wykonujemy dla pierwszych bitów obu liczb. Tym razem oba są równe zero, więc w wyniku także otrzymujemy zero. Następnie wykonujemy operację dla bitów numer trzy obu liczb. Wynikiem działania dla argumentów równych jeden i zero jest ponownie zero. Dokonujemy tej samej operacji dla bitów numer cztery obu liczb - w efekcie wykonania operacji AND na obu argumentach równych jeden, otrzymujemy jedynkę. Wynikiem całej operacji jest więc liczba 1000 w systemie dwójkowych. Liczba ta w systemie dziesiętnym jest równa osiem i właśnie ona zostanie wyświetlona na ekranie.

Następną operacją jest operacja OR . Po zapisaniu jej podobnie jak poprzednio otrzymujemy:



1100 (12 w systemie dziesiętnym)

OR

1001 (9 w systemie dziesiętnym)

====

1101 (13 w systemie dziesiętnym)

Algorytm działania jest identyczny jak poprzednio, tylko zamiast operacji AND wykonujemy operację OR. Wynikiem tej operacji jest jedynka, gdy którykolwiek z argumentów jest jedynką, stąd też tylko dla bitu pierwszego otrzymaliśmy zero, a reszta bitów jest równa jeden.

Przedostatnią operacją jest XOR :



1100 (12 w systemie dziesiętnym)

XOR

1001 (9 w systemie dziesiętnym)

====

0101 (5 w systemie dziesiętnym)

I znowu wykonujemy identyczne operacje, zamieniając tylko operację na XOR. Dla przypomnienia - wynikiem tej operacji jest jedynka, gdy tylko jeden z argumentów jest równy jeden.

Ostatnią operacją jest operacja NOT . Jak zapewne zauważyłeś po uruchomieniu programu, wynikiem operacji NOT 9 jest liczba minus dziesięć, którą binarną reprezentacją jest 11110110. A oto jak ją otrzymaliśmy:



NOT

00001001 (9 w systemie dziesiętnym)

========

11110110 (-10 w systemie dziesiętnym)

Jest to najprostsza z operacji logicznych - ja widać odwraca po prostu wszystkie bity argumentu.