| ← pole a ukazatele | C/C++ | preprocesor → |
V této kapitole si ukážeme operátory, které můžete v jazyku C používat. Některé speciální operátory (jako např. přetypování) už znáte, a naopak použití jiných si vysvětlíme až v některé z příštích kapitol. Po výčtu všech operátorů bude na konci jeden velký příklad, kde si použití operátorů ukážeme. U většiny operátorů však bude na vás, aby jste si jejich chování vyzkoušeli ve vlastních příkladech.
Operátory lze rozdělit několika způsoby. Mimo jiné na unární, binární, ternární, neboli na operátory s jedním, dvěma nebo třemi operandy. Operandy jsou data (většinou čísla), se kterými operátory (např. plus) pracují. Operátory se také rozdělují na aritmetické, bitové, relační a logické. Čtěte dále.
| Operátor | Význam |
|---|---|
| +,- | unární plus a mínus, |
| & | reference (získání adresy objektu) |
| * | dereference (získání objektu dle adresy) |
| ! | logická negace |
| ~ | bitová negace |
| ++, -- | inkrementace a dekrementace hodnoty |
| (typ) | přetypování |
| sizeof | operátor pro získání délky objektu nebo typu! |
Unární plus a mínus určuje znaménko čísla. Například ve výrazu 5 + (-4) je plus binární operátor (má dva operandy) a mínus je unární operátor (vztahuje se jen ke čtyřce).
S operátory reference & a * dereference jsme se již setkali při práci s ukazateli.
V jazyce C neexistuje datový typ boolean. Pokud potřebujeme někde získat nebo uchovat hodnotu pravda/nepravda (TRUE/FALSE), můžeme k tomu využít např. typ int. V jazyce C je totiž vše nenulové považováno za TRUE a ostatní (včetně. např. prázdného řetězce, tj řetězce, jehož první znak je nulový znak) za FALSE. Nula je tedy FALSE a jiné číslo (nejčastěji se používá jednička) TRUE.
Výsledkem logické negace ! je TRUE nebo
FALSE, což jazyk C vyhodnocuje jako 1 nebo 0. Například
!5 je 0.
Bitová negace ~ je však něco úplně jiného.
Bitová negace obrací jednotlivé bity ve výrazu. Takže například
~0x05 je 0xFA
(~00000101 je
11111010).
Inkrementace ++ a dekrementace -- může být zapsáno jak před výrazem, tak za ním Zvyšují, resp. snižují hodnotu čísla o jedničku. Pokud leží ++ před proměnnou, nejdříve se zvýší její hodnota a pak se proměnná použije ve výrazu (pokud v nějakém je), leží-li ++ za proměnnou, nejdříve se proměnná použije ve výrazu a pak se teprve zvýší její hodnota. Obdobně je to u dekrementace --.
Například:
y = 5; x = ++y; // y se inkrementuje na 6 a poté se dosadí 6 do x x = y++; // do x se dosadí y (6) a pak se y inkrementuje (na 7)
Operátor sizeof vrací velikost datového typu nebo objektu v bytech.
float y; int x = sizeof(float); x = sizeof(y);
Priorita operátorů stanovuje, která část výrazu se vyhodnotí dříve, pokud to není závorkami určeno jinak. Klasickým příkladem je vyhodnocení výrazu x = 1+1*0;. Výsledkem bude samozřejmě číslo 1, protože operátor násobení má větší prioritu než operátor sčítání.
Priorita operátorů je v jazyku C velice komplikovaná záležitost a proto se omezím na stručnou radu: používejte závorky!
Ovšem pozor! Pořadí vyhodnocení inkrementace (dekrementace) ve výrazu není normou jazyka C nijak dáno. Tudíž není zaručeno, že každý překladač pořadí (rozuměj prioritu) výpočtu vyhodnotí stejně. Vlastně i jeden překladač se na různých místech může v zájmu optimalizace programu rozhodnout k různému pořadí vyhodnocování výrazu (obdobně to platí i pro funkce, viz níže).
Následující konstrukce (a jí podobné) by jste se měli vyhýbat jako čert kříži. Odhalit proč se program nechová jak má kvůli jinému vyhodnocování různými překladači bývá zdlouhavé.
y = 5; x = y+++++y;
Po této operaci bude y rovno sedmi (dvakrát se inkrementuje). Ale co x? Může s to vyhodnotit jako 5+6, nebo jako 5+7? V tomto případě by vám ani závorky nepomohli. Překladač si totiž řekne: první y se má zvýšit až po použití ve výrazu, tj první y bude 5. A teď si může říct 2 věci: y už jsem použil, můžu ho inkrementovat. Nebo si to neřekne a přejde na vyhodnocování druhého y, které inkrementuje (na 6), obě čísla sečte (5+6) a až teď teprve se rozhodne, že provede postfixovou inkrementaci y a zvýší jej na 7.
Taktéž u volání funkcí není jasné, která se ve výrazu zavolá dříve. Podívejte se na následující příklad.
x = f1() + f2();
Pokud funkce (kromě toho že vracejí nějaké číslo, které se pak sečte) vypisují na obrazovku nějaký text, nemůžete si být nikdy jistí, který text se vypíše jako první.
| Operátor | Význam |
|---|---|
| = | přiřazení |
| +,-,*,/ | plus,mínus,krát,děleno |
| % | zbytek po celočíselném dělení (modulo) |
| <<, >> | bitový posun vlevo, vpravo |
| & | bitové AND |
| | | bitové OR |
| ^ | bitové XOR |
| && | logické AND |
| || | logické OR |
| . | tečka, přímý přístup ke členu struktury |
| -> | nepřímý přístup ke členu struktury |
| , | čárka, oddělení výrazů |
| < | menší než |
| > | větší než |
| <= | menší nebo rovno |
| >= | větší nebo rovno |
| == | rovnost |
| != | nerovnost |
Při bitovém posunu vlevo (vpravo) se poslední levý (pravý) bit
ztrácí a zprava (zleva) je dosazena nula. Bitové operace je možné
provádět jen s celočíselnými hodnotami. Při posunu čísel se
znaménkem se však znaménko zachovává. Vlevo od operátoru je objekt, ve kterém
se bity posouvají, vpravo od operátoru je číslo určující kolikrát se bity
posunou.
U logického AND a OR, výrazů >= atp. je výsledkem TRUE nebo
FALSE, tedy 1 nebo 0.
Operátor přiřazení lze kombinovat s některými výpočty: +=, -=, *-, /=, <<=, >>=, &=, |=, ^=.
| Výraz | Ekvivalent |
|---|---|
| x -= 5; | x = x - 5; |
| x *= x; | x = x * x; |
| x >>= 2; | x = x >> 2; |
Podmíněný operátor ? : je ternárním operátorem (má 3 operandy). Prvním operandem je výraz, který se vyhodnotí jako logický výraz (TRUE nebo FALSE). Pokud se vyhodnotí jako TRUE, výsledkem bude druhý operand (mezi ? a :), jinak třetí operand.
printf("%s\n", (x > y) ? "x je > y" : "x je < y");
1: /*------------------------------------------------*/ 2: /* operator.c */ 4: #include <stdio.h> 5: #include <limits.h> /* ziskame konstanty UINT_MAX a INT_MIN */ 7: int main(void) 8: { 9: int x, y, z; 10: int pole[] = { 5, -10, 15, -20, 25, -30 }; 11: unsigned int delka_pole; 12: x = y = z = 10; 14: x = y++; 15: z++; 16: printf("%3d %3d %3d\n", x, y, z); 17: printf("%3d %3d %3d\n", ++x, y++, ~z); 18: printf("%3d %3d %3d\n", x, y, z); 20: delka_pole = sizeof(pole) / sizeof(pole[0]); 21: printf("Mate %2u bitovy prekladac.\n", sizeof(int) * 8); 22: printf("Pole pole[] zabira %2u bytu.\n\n", sizeof(pole)); 24: printf("UINT_MAX = %u = %u\n", UINT_MAX, ~0); /* UINT_MAX = max velikost cisla v typu unsigned int */ 25: printf("INT_MIN = %i = %i \n", INT_MIN, 1 << ((sizeof(int) * 8) - 1)); /* posunu jednicku az do "nejlevejsiho bitu" */ 26: printf("-51 >> 1 = %i\n\n", -51 >> 1); 27: printf("Zadejte index pole (od 0 do %2u): ", delka_pole - 1); 29: scanf("%i", &x); 30: printf("Zadal jsi %i\n", x); 32: /* musi se zkontrolovat platnost zadaneho indexu pole !! */ 33: x = (x < 0) ? 0 : x; 34: x = (x >= delka_pole) ? delka_pole - 1 : x; 35: printf("pole[%u] = %i\n", x, pole[x]); 37: return 0; 38: } 40: /*------------------------------------------------*/
Výstup z programu:
10 11 11 11 11 -12 11 12 11 Mate 32 bitovy prekladac. Pole pole[] zabira 24 bytu. UINT_MAX = 4294967295 = 4294967295 INT_MIN = -2147483648 = -2147483648 -51 >> 1 = -26 Zadejte index pole (od 0 do 5): -11 Zadal jsi -11 pole[0] = 5
Protože mám 32 bitový překladač, typ int zabírá 32 bitů, tj 4 bajty. Proto pole zabírá celkem 24 bajtů.
Pokud jste zmateni z výpočtu INT_MIN, vzpomeňte si co jsme si říkali o dvojkové soustavě a doplňkovém kódu.
Všimněte si, jakým způsobem jsem získal meze pro index pole[]. Pole je vždy indexováno od 0. Počet prvků však může být různý. Kdyby jste v kontrole horní meze napsali natvrdo x = x>5 ? 5 : x;, museli by jste při změně počtu prvků v poli změnit i tento výraz. Ve velkém zdrojovém kódu by jste to mohli snadno přehlédnout (nehledě na to, že je to pracné hledání). Takhle se již nemusíte o nic starat.
Operátor ? : lze použít i trochu jinak. Jestlipak správně pochopíte význam následujícího výrazu?
z > x ? x : y = z;1)
Jestli si nejste jisti, tak si to vyzkoušejte v programu. První co vás napadne jako odpověď nemusí být hned správně :-).
Čistě jenom pro zopakování ukážu jak lze využít hodnotu NULL, společně s podmíněným operátorem.
1: /*------------------------------------------------*/ 2: /* null1.c */ 4: #include <stdio.h> 6: int main(void) 7: { 8: float *uk = NULL; 9: float p[] = { 10.2, 5.1, 0.6 }; 11: printf("%s\n", uk == NULL ? "Ukazatel neni inicializovan" : 12: "Ukazatel lze pouzit"); 13: printf("%f\n", uk == NULL ? 0.0 : uk[0]); 15: uk = p; 17: printf("%s\n", uk == NULL ? "Ukazatel neni inicializovan" : 18: "Ukazatel lze pouzit"); 19: printf("%f\n", uk == NULL ? 0.0 : uk[0]); 20: return 0; 21: } 23: /*------------------------------------------------*/
Výstup z programu:
Ukazatel neni inicializovan 0.000000 Ukazatel lze pouzit 10.200000
1) Je možné, že tuto konstrukci vám překladač ani nedovolí přeložit. Můžete si pomoct se závorkami, ale to už pak nebude taková sranda dešifrovat co to vlastně dělá >:-).
| ← pole a ukazatele | C/C++ | preprocesor → |
