Wstęp
Ogólnie operatory możemy podzielić na 3 kategorie: dwuargumentowe, jednoargumentowe i jeszcze jeden, samotny w swojej grupie operator wyrażenia warunkowego ( ? : ) który posiada 3 argumenty.
Operatory dwuargumentowe przyjmują 2 argumenty, rozdzielone właśnie tym operatorem. Argumenty nazywamy odpowiednio lewym i prawym.
Operatory jednoargumentowe przyjmują tylko jeden argument, który powinien być określony z lewej lub z prawej strony operatora (w zależności od operatora i jego użycia).
Operator przypisania
Operator przypisania, czyli operator = służy do umieszczenia wartości znajdującej się z prawej strony w zmiennej po lewej stronie. Po prawej może znajdować się dowolne wyrażenie, po lewej musi znajdować się zmienna.
a = 10 // przypisze wartość 10 do zmiennej aUmieszczenie czegokolwiek innego po jego lewej stronie poskutkuje pięknym błędem kompilacji.
10 = a // zwróci błąd, nie możemy przecież nic przypisać do 10, nie jest zmienną! 10 = 12 // również zwróci błąd 10 = 10 // to też jest błąd, nie ważne że 10 jest równe 10, to nie jest operator porównaniaCo ciekawe, operator przypisania ZWRACA wartość. Wartością tą jest wartość prawego wyrażenia, dzięki temu możemy takiego operatora użyć kilkukrotnie w 1 instrukcji:
a=b=c=12 // zmiennej c przypisze wartość 12, następnie zrobi to samo dla wartości b oraz a
Dzięki temu możemy użyć takiego operatora w warunku if:
if ( x = funkcja(y) )Wiele osób pewnie pomyśli, że powyższy kod porówna x z wartością zwróconą przez funkcję. Otóż nie zrobi tego! Przypisze on do zmiennej x wartość zwróconą przez funkcję, a następnie tą samą wartość zwróci. Tak więc jeśli funkcja zwróci true, kod wewnątrz if się wykona, jeśli zwróci false, kod się nie wykona. Nie jest ważne co do tej pory siedziało w zmiennej x, na dodatek zostanie to zastąpione nową wartością!
Bystre oko zauważy, że kompilator AMXX zwróci nam warning przy kompilacji tej linii. Aby kompilator uciszyć, wystarczy objąć warunek dodatkowymi nawiasami:
if (( x = funkcja(y) ))Nie zmieni to działania warunku, ale poinformuje kompilator, że WIEMY co robimy i nie pomyliliśmy się używając = zamiast == w tym miejscu.
Operatory arytmetyczne
Operatory arytmetyczne wykonują proste działania arytmetyczne i zwracają ich wynik. Wszystkie operatory arytmetyczne są dwuargumentowe i zaliczamy do nich +, -, *, / oraz %. Wykonują one po kolei: dodawanie, odejmowanie, mnożenie, dzielenie (zwrócenie wyniku z dzielenia), dzielenie (zwrócenie reszty z dzielenia). Przykłady:
10 + 20 // 30 20 - 2 // 18 14 * 3 // 42 12 / 2 // 6 13 / 2 // również 6 ! 13.0 / 2 // 6.5 13 % 2 // 1
Dodatkowemu wyjaśnieniu podlegają operatory dzielenia. Pierwszy z nich dokona dzielenia całkowitego (tj zaokrągli wynik z dzielenia do jedności w dół) jeśli po jego obu stronach znajdą się liczby typu całkowitego. Dokona jednak dokładnego dzielenia, gdy choć z jednej strony znajdzie się liczba zmiennoprzecinkowa. Drugi z operatorów dokona zawsze dzielenia całkowitego i zwróci jego resztę.
Operatory znaku liczby
Są to operatory - i + dla których podany został tylko 1 argument, po prawej stronie. Skutkiem jest zachowanie (dla +) lub zmiana na przeciwny (dla -) znak liczby. Wyobrazić sobie można to tak, jakby po lewej stronie wirtualnie stało zawsze 0
Operatory te można rozróżnić tylko, gdy po lewej stronie nie znajduje się nic, znajduje się inny operator lub znajduje się nawias.
Operatory bitowe
Istnieje 7 operatorów bitowych, jeden jednoargumentowy i sześć dwuargumentoych.
Operatorem jednoargumentowym jest ~ czyli negacja bitowa. Przyjmuje on argument po swojej PRAWEJ stronie:
~14 // dobrze 14~ // żle, argument musi być po prawej!
Operator zwraca negację bitową podanego argumentu.
Operatorami dwuargumentowymi są operatory &, |, ^, <<, >> oraz >>>. Trzy pierwsze z nich dla podanych argumentów zwracają odpowiednio ich koniunkcję bitową (iloczyn bitowy), ich alternatywę bitową (suma bitowa) oraz ich alternatywę rozłączną (bitową różnicę symetryczną, XOR).
Pozostałe trzy dokonują przesunięcia bitowego. Argument po lewej stronie jest liczbą przesuwaną, a argument po prawej oznacza o ile bitów argument po lewej zostanie przesunięty. << dokonuje przesunięcia w lewo, >> w prawo arytmetycznie, a >>> w prawo logicznie.
Więcej o operatorach bitowych tutaj: Operacje bitowe
Operatory skróconego przypisania
Operator skróconego przypisania jest niczym innym, jak połączeniem operatora arytmetycznego lub bitowego z operatorem przypisania. Dla operatora •:
a •= 10jest równoznaczne:
a = a • 10Oczywiście operator • w języku pawn nie istnieje, należy go zastąpić dowolnym operatorem arytmetycznym lub bitowym.
Inaczej mówiąc: operator ten wykona działanie na argumencie lewym i prawym tak jakby to miało miejsce przy zwykłym operatorze arytmetycznym lub bitowym, jednak wynik tego działania zapisze również w lewym argumencie.
Oznacza to, że tak jak dla operatora przypisania, zwraca on wartość przypisywaną oraz wymaga by po jego lewej stronie znajdowała się zmienna.
Inkrementacja i dekrementacja
Są to operatory ++ oraz --, są operatorami jednoargumentowymi i występują w 2ch odmianach: post i pre. Postinkrementacja i postdekrementacja następują, gdy argument zostanie podany z lewej strony. Preinkrementacja i predekrementacja gdy zostanie podany z prawej strony. Przykłady:
i++ // postinkrementacja ++i // preinkrementacja --i // predekrementacja i-- // postdekrementacja
Operatory te zwiększają (inkrementacja) lub zmniejszają (dekrementacja) wartość liczby o 1. Jako, że zapisują one wynik w zmiennej podanej jako argument, przyjmują za argument WYŁĄCZNIE zmienne. Nie mogą być to liczby ani inne wyrażenia. Post od pre różni się zwracaną wartością. Postinkrementacja zwraca wartość przed wykonaniem działania, preinkrementacja wartość po wykonaniu działania. Preinkrementacja jest bezpośrednim odpowiednikiem zapisu:
i += 1Postinkrementację można zapisać inaczej tylko jako funkcję:
postinkrementacja(&i) { new j = i; i += 1 return j; }
Operatory logiczne
Zanim o samych operatorach, trochę o samych stanach logicznych. W języku pawn istnieją 2 stany logiczne: prawda i fałsz, które są swoimi wzajemnymi przeciwieństwami. Fałszem jest wszystko o wartości zero, prawdą wszystko o wartości różnej od zera! To oznacza, że prawdą jest nie tylko 1, ale też 2, 10, 2000 a nawet liczby ujemne czyli -300 lub -1!
W związku z tym, że wartości dla prawdy jest de facto nieskończenie wiele (właściwie to skończenie, ale i tak mnóstwo), przyjęło się że każdy operator logiczny będzie zwracał 1 jako prawdę logiczną. Zważmy jednak na to, że nadal może on przyjąć dowolną wartość i jeśli jest ona różna od zera, potraktuje ją jako prawdę !!!
Operatorami logicznymi są: !, ==, !=, <, >, <=, >=, && oraz ||.
Pierwszy z nich, czyli ! jest operatorem jednoargumentowym i przyjmuje argument, tak jak operator negacji bitowej, po swojej prawej stronie. Zwraca on logiczne przeciwieństwo danego wyrażenia. Czyli jeśli jako argument dostanie prawdę, zwróci fałsz, jeśli fałsz to zwróci prawdę.
Reszta z nich przyjmuje 2 argumenty i możemy je podzielić na 2 kategorie: operatory porównania i operatory and i or.
Operatory porównania po prostu porównują 2 wartości ze sobą i zwracają prawdę lub fałsz jeśli ich wewnętrzny warunek został spełniony.
== sprawdzi czy wartości są równe
!= sprawdzi czy wartości są różne
> sprawdzi czy wartość po lewej jest większa od wartości po prawej
< sprawdzi czy wartość po lewej jest mniejsza od wartości po prawej
>= sprawdzi czy wartość po lewej jest większa lub równa wartości po prawej
<= sprawdzi czy wartość po lewej jest mniejsza lub równa wartości po prawej
Operator && jest to operator AND, sprawdza on czy zarówno po lewej jak i po prawej znajduje się prawda logiczna. Jest dość specyficznym operatorem, ponieważ najpierw sprawdzi (i jednocześnie wykona odpowiednie działania) czy po prawej jest prawda, a dopiero później po lewej. Jeśli po prawej znajdzie się fałsz, wszystko po jego lewej stronie NIE ZOSTANIE wykonane!
Oznacza to, że:
if (is_user_connected(id) && has_user_jetpack(id))kod wewnątrz funkcji has_user_jetpack NIE ZOSTANIE NIGDY wykonany, jeśli gracz nie jest połączony do serwera!
Operator || jest operatorem OR, sprawdza on czy po lewej lub po prawej znajduje się prawda logiczna. On również zachowuje się specyficznie, gdyż nie wykona nigdy kodu po jego prawej jeśli po lewej znajduje się prawda.
Oznacza to, że:
if (has_user_jetpack(gracz1) || has_user_jetpack(gracz2))sprawdzenie dla drugiego gracza czy posiada jetpack NIGDY SIĘ NIE WYKONA jeśli pierwszy gracz jetpack posiada.
Operator wyrażenia warunkowego
Operator ten przyjmuje 3 argumenty, pierwszy z nich wstawiamy przed znakiem zapytania, drugi pomiędzy znakiem zapytania, a dwukropkiem, a trzeci z nich za dwukropkiem.
Działanie operatora jest dość proste, jeśli 1 argument jest prawdą, zwróci on 2 argument, jeśli fałszem, zwróci 3 argument. Przykład:
is_user_connected(id)?"gracz jest na serwerze":"gracza nie ma na serwerze"
Nawiasy
Prócz tych wszystkich operatorów występują również nawiasy. Pierwszy z nich, czyli nawias okrągły () może służyć do 2ch rzeczy: może grupować (jak w matematyce) odpowiednie wyrażenia, zmieniając ich kolejność wykonywania oraz może być składnikiem definicji lub wywołania funkcji.
Drugi z nich, nawias kwadratowy [] służy do definiowania tablicy lub do wywoływania konkretnego elementu tej tablicy.
Priorytety i kolejność obliczeń
Każdy z operatorów posiada pewien priorytet, który determinuje kolejność w jakiej operatory zostaną wywołane jeśli znajdują się w 1 instrukcji. Dodatkowo każdy z operatorów posiada kierunek łączności, który determinuje w jakiej kolejności zostaną wykonane działania dla operatorów o tym samym priorytecie.
Priorytety od najwyższego do najniższego:
- Nawiasy
- wybór elementu tablicy, wywołanie funkcji, postinkrementacja, postdekrementacja
- !, ~, + i - (jako znak liczby), preinkrementacja, predekrementacja
- *, /, %
- + i - (jako operatory arytmetyczne)
- <<, >>, >>>
- <, <=, >, >=
- == !=
- &
- ^
- |
- &&
- ||
- ?: (operator wyrażenia warunkowego)
- wszystkie operatory przypisania