C/C++ (6) - Operátory

Pomocí operátorů lze v Céčku nejen sečíst nebo vynásobit dvě čísla, ale třeba i zavolat funkci, zvětšit hodnotu proměnné o 1 nebo získat velikost výrazu.

3.11.2004 13:00 | Jan Němec | přečteno 54456×

Operátory

Operátory zná každý z výrazů v matematice. Intuitivně: operátor vezme nějaký počet operandů (nejčastěji dva) a z jejich hodnot vypočítá další hodnotu, která je výsledkem výrazu. Pokud má výraz více operátorů, pořadí vyhodnocování určuje priorita, asociativita a závorky.

1 + 2 * 3 znamená 1 + (2 * 3) a ne (1 + 2) * 3    (* má vyšší prioritu než +)
1 - 1 - 1 znamená (1 - 1) - 1 a ne 1 - (1 - 1)    (- je asociativní zprava)

V Céčku je to podobné, jen s několika výhradami. Operátorem zde je téměř cokoli od aritmetických operátorů přes přiřazení, predikátové symboly, spojky z výrokové logiky až po operátor zapomenutí a dokonce i volání funkce. Narozdíl od matematiky mají některé operátory vedlejší efekt, například změní hodnotu operandu po vypočtení výrazu.

Z operátorů lze vytvořit složitý výraz. V obecném případě norma jazyka nezaručuje pořadí vyhodnocování podvýrazů ani to, že celý strom výrazu bude vyhodnocen. Například u exp1 + exp2 se nelze spolehnout na to, že bude exp1 vyhodnocen před exp2 a v případě exp1 * exp2 nemusí být jeden z výrazů vyhodnocen vůbec (pokud ten druhý vyjde nula). U jednoduchých podvýrazů exp1 a exp2 programátorovi na pořadí vyhodnocení nezáleží, ale pokud podvýrazy například obsahují volání funkcí s nějakým vedlejším efektem, může být pořadí důležité. V tom případě musí programátor výraz rozepsat do dvou příkazů. Některé operátory naopak pořadí vyhodnocování přesně specifikují, ale jedná se spíše o výjimky, na které vždy upozorním.

V souvislosti s operátory se vyskytuje pojem l-hodnota. Je to výraz, který označuje nějaké místo v paměti, kam můžeme zapisovat. Nejčastější l-hodnotou je proměnná, naopak konstanta l-hodnotou není. Zhruba řečeno, l-hodnota je cokoli, co může být na levé straně přiřazení.

Jazyk C má 15 priorit operátorů, menší číslo znamená vyšší prioritu. Ani zkušený programátor obvykle nezná přesně priority jednotlivých operátorů, proto se je dobrým zvykem u složitějších výrazů hodně používat závorky.

PrioritaOperátoryAsociativita
1 .   ->   ()   []  zleva
2 +   -   ++   --   !   ~   (přetypování)   &   *   sizeofzprava
3 *   /   %zleva
4 +   -  zleva
5 <<   >>zleva
6 <   >   <=   >=zleva
7 ==   !=zleva
8 &zleva
9 ^zleva
10 |zleva
11 &&zleva
12 ||zleva
13 ?:zprava
14 =   +=   -=   *=   /=   %=   <<=   >>=   &=   |=   ^=   zprava
15 ,zleva

Něteré operátory už známe. Z první skupiny je to volání funkce, operátor (). Prvním operandem je ukazatel na funkci (v našem případě to byl zatím vždy, název funkce, ale to je v Céčku vlastně konstantní ukazatel do kódu programu v paměti), případnými dalšími operandy jsou parametry funkce. V druhé skupině jsme se setkali s přetypováním. Známe i operátor sizeof, ten má syntaxi podobnou volání funkce s jedním parametrem a spočítá velikost výrazu nebo i typu v paměti.

printf("int má %i byty a celočíselná konstanta také %i\n",
  sizeof(int), sizeof(5));

Ve třetí a osmé skupině jsou operátory * a &, dereference ukazatele a adresa, známe také ve 14. skupině =. Rovnítko, operátor přiřazení, používáme především kvůli jeho vedlejšímu efektu (do levého operandu se přiřadí hodnota pravého), ale občas se hodí i jeho návratová hodnota, kterou je pravý operand.

i = j = k = 0;

Díky asociativitě zprava se výraz vyhodnotí jako

i = (j = (k = 0));

a jediným příkazem jsme tak vynulovali tři proměnné. Nejprve se do k uložila 0, hodnotou výrazu k = 0 je 0, která se tak dostane i do j a stejným způsobem nakonec i do proměnné i.

Nejznámějšími operátory jsou ty aritmetické. Ve druhé skupině jsou unární + a -, například +5 nebo -128 a ve třetí *, / a %. Hvězdičkou se násobí, lomítkem dělí a procento je zbytek po celočíselném dělení. Je důležité vědět, že / je jak celočíselné, tak i reálné dělení. Je-li alespoň jeden z operandů reálného typu, použije se dělení reálné, v opačném případě celočíselné. Chceme-li reálně dělit dvě celá čísla, je třeba použít přetypování nebo za konstantou explicitně uvést desetinnou tečku.

int i = 7, j = 2;
double f;
f = 7 / 2;
printf("%f\n", f); /* 3.000000 nepříjemné překvapení ? */
f = 7 / 2.0;
printf("%f\n", f); /* 3.500000 */
f = i / j;
printf("%f\n", f); /* 3.000000 nepříjemné překvapení ? */
f = i / (double) j;
printf("%f\n", f); /* 3.500000 */

V programech se často vyskytují konstrukce typu i = i + 1 nebo i = i * 2, tedy kombinace přiřazení s jedním dalším operátorem, kde levým operandem přiřazení i aritmetického operátoru je jedna a ta samá proměnná. Céčko zde programátorům ulehčuje život a nabízí sadu operátorů ze 14. skupiny. Místo i = i + 1 tak lze psát i += 1, místo i = i * 2 píšeme i *= 2 a podobně.

Úplně nejčastěji se používá zvětšení nebo zmenšení o jedničku. Zápis i += 1 nebo i -= 1 by se někomu mohl zdát stále moc dlouhý, proto C nabízí operátory ++ a --. Místo i = i + 1 lze psát i += 1 nebo také i++, případně ++i. Výraz i = i - 1 zcela analogicky nahradíme i -= 1 nebo i--, případně --i. Mezi prefixovou a postfixovou verzí operátorů ++ a -- je následující rozdíl: ++i nejprve zvětší proměnnou i o jedničku a výsledná hodnota i je návratovou hodnotou celého výrazu. Naopak u i++ je návratovou hodnotou původní i.

int i = 5;
printf("%i\n", i++); /* 5 */
/* v i je teď 6 */
printf("%i\n", ++i); /* 7 */

Pokračování příště

V příštím díle probereme logické operátory a dostaneme se k podmínce.

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=486