Proměnné, základní vstup a výstup BI-PA1 Programování a Algoritmizace 1 Miroslav Baĺık, Ladislav Vagner a Josef Vogel Katedra teoretické informatiky a Katedra softwarového inženýrství Fakulta informačních technologíı České vysoké učení technické v Praze xvagner@fit.cvut.cz, vogeljos@fit.cvut.cz 10., 12. a 13. října 2017
Přehled Bity (bits), bajty (bytes), pamět počítače. Od bajtů k informacím. Datový typ int. Kódování celých čísel, dvojkový doplněk. Datový typ char. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 2/46
Bity, bajty, pamět Bit nejmenší jednotka informace: hodnota 0 nebo 1, jednoduše implementovatelný v reálném světě (vyšší nebo nižší napětí, bistabilní klopný obvod, nabitý nebo nenabitý kondenzátor,... ). Bajt (byte) typicky 8 bitů: 2 8 = 256 různých hodnot, procesor má typicky přístup k bajtům, nikoli k jednotlivým bitům. Adresa jednoznačná identifikace bajtu v paměti: pořadové číslo bajtu (pozice bajtu), počítaná od počátku pamět ového prostoru, pamět ového čipu,.... Kapacita paměti celkový počet bajtů: Metrika: 1 KB = 1000 B, 1 MB = 1000 KB = 1000000 B, 1 GB = 1000 MB = 1000000 KB = 1000000000 B,..., Binárně - základem 2 10 = 1024 (IEC 60027-2): 1 KiB = 1024 B, 1 MiB = 1024 KiB = 1048576 B, 1 GiB = 1024 MiB = 1048576 KiB = 1073741824 B,.... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 3/46
Pamět Operační pamět uchovává program a data v době běhu programu: velmi rychlá, obsah paměti je ztracen při výpadku napájení (volatile), drahá (cena za bajt). Externí pamět disk, CD/DVD, páska,... : o několik řádů pomalejší, obsah paměti zůstává zachován při vypnutí napájení (non-volatile), komplikovanější přístup k datům, levnější (cena za bajt). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 4/46
Od bajtů k informacím Počítač (strojový kód) pracuje s bajty: nestará se o význam hodnot, nesnaží se jim porozumět, má přesná pravidla, jak bajty zpracovat (např. jak je sečíst). Uživatelé (lidé) potřebují ukládat informace (celá čísla, dekadická čísla, znaky, znakové řetězce,... ): aby mohla být informace uložena do paměti, musí být zakódována do jednoho či více bajtů, zakódovaná informace může umožňovat jen některé operace (např. znakové řetězce nelze odmocňovat). Vyšší programovací jazyky obvykle poskytují systém typů. Typ: reprezentuje nějaký druh informací (číslo, řetězec,... ), definuje množinu možných hodnot, definuje množinu dovolených operací, definuje kódování (jak je informace uložena v bajtech, kolik bajtů je třeba pro uložení informace). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 5/46
Datové typy Programátor se ve vyšších programovacích jazycích nemusí starat o vnitřní reprezentaci informací: informace jsou uloženy v proměnných, proměnné mohou obsahovat určité typy hodnot, typicky proměnné mají určitý datový typ, který se v průběhu existence proměnné nemůže měnit. Příklad datový typ int v jazyku C: množinou hodnot je interval celých čísel od 2147483648 do 2147483647 (proč?), povolené operace jsou: aritmetické operace (+,,, /,... ), relační operace (<, <=, ==,... ), přiřazení hodnoty (=, + =,... ), další operace. Programovací jazyky mají obvykle několik primitivních datových typů (např. int). Další datové typy mohou být definovány programátorem (strukturované datové typy, pole,... ). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 6/46
Proměnné Proměnná je pojmenovaný datový objekt obsahující nějakou hodnotu. Hodnota uložená v proměnné se v průběhu života proměnné může měnit. Proměnné jsou identifikovány svými jmény jednoznačnými identifikátory. Deklarace proměnné (jazyk C): int alpha; /* alpha je jméno proměnné */ Následující příkaz vypíše hodnotu proměnné typu int: printf ( "%d\n", alpha ); /* \n přidá nový řádek */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 7/46
Proměnné (pokračování) Přiřazení se použije pro změnu hodnoty uložené v proměnné: /* alpha má nějakou hodnotu */ alpha = 20; /* hodnota proměnné alpha je nyní 20, původní hodnota je zapomenuta */ Operátor přiřazení není rovnost: /* alpha má nějakou hodnotu */ alpha = 20; /* hodnota alpha je nyní 20 */ alpha = alpha + 1; /* ok, hodnota alpha je nyní 21 */ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 8/46
Proměnné (pokračování) #include <stdio.h> int main ( void ) { int alpha = 0; } printf("%d\n", alpha); alpha = 37; printf("%d\n", alpha); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 9/46
Proměnné inicializace #include <stdio.h> int main ( void ) { int alpha; /* proměnná alpha není inicializovaná! */ printf("%d\n", alpha); /* co je výstupem? */ alpha = 37; printf("%d\n", alpha); /* výstup je nyní 37 */ return 0; } M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 10/46
Globální proměnné #include <stdio.h> int alpha; /* globální proměnné jsou vždy inicializovány nulovými bajty */ int main ( void ) { printf("%d\n", alpha); /* výstup iniciální hodnoty globální proměnné je 0 */ alpha = 37; printf("%d\n", alpha); /* výstup je nyní 37 */ return 0; } M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 11/46
Funkce printf Knihovní funkce printf se používá pro: výpis fixního řetězce znaků, výpis hodnoty proměnné (hodnot proměnných), výpis hodnoty proměnné (hodnot proměnných) ve formátu definovaném uživatelem, výpis hodnoty výrazu (nikoli pouze hodnoty uložené v proměnné). Funkce printf konvertuje binární hodnotu(y) proměnné(ých) či výrazu(ů) do znakové podoby. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 12/46
Funkce printf, typ int #include <stdio.h> int main ( void ) { int a, b; } a = 10; b = 20; printf("a = %d\n", a); /* a = 10 */ printf("%d + %d = %d\n", a, b, a + b); /* 10 + 20 = 30 */ printf("%3d + %3d = %05d\n", a, b, a + b); /* 10 + 20 = 00030 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 13/46
Funkce scanf Standardní funkce scanf: čte znaky (např. stisky kláves klávesnice), konvertuje je, ukládá binární hodnotu(y) do proměnné(ých). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 14/46
Funkce scanf, typ int #include <stdio.h> int main ( void ) { int x; } printf("napis cislo:\n"); scanf( "%d", &x ); /* povšimněme si & */ printf("cislo bylo %d\n", x ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 15/46
Funkce scanf Jak pracuje funkce scanf (datový typ int): přeskočí (ignoruje) všechny bílé znaky ze vstupu (mezery, nové řádky, tabelátory), pokusí se přečíst hodnotu (začne prvním znakem, jež není bílý; pro typ int musí být první znak bud dekadická číslice nebo znaménko + či, přečte všechny dekadické číslice, uloží binární reprezentaci čísla do uvedené proměnné, čtení končí na prvním znaku, který není dekadickou číslicí (pro typ int). To je např. mezera, odřádkování, písmeno,... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 16/46
Funkce scanf #include <stdio.h> int main ( void ) { int x, y; } printf("vstup souradnic:\n"); scanf( "%d %d", &x, &y ); /* všimněme si, že jsou čteny hodnoty dvou proměnných */ printf("souradnice jsou (%d,%d)\n", x, y ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 17/46
Funkce scanf časté otázky Jak funkce scanf pracuje za specifických podmínek: Co se stane, když na vstupu nejsou žádné znaky? Funkce prostě čeká na vstup znaků. Kdy je vstup vlastně čten? Vypadá to, že nic není přečteno, dokud není stisknuta klávesa Enter. Skutečně, vstup je zpracován funkcí scanf teprve po stisknutí klávesy Enter. Důvodem je operační systém (OS). Znaky jsou OS ukládány do vyrovnávací paměti (bufferu) řádku a celý řádek je předán ke zpracování až po stisknutí klávesy Enter. Toto chování OS může být změněno zákazem bufferování. Mohu zjistit, že vstup je špatně (např. na vstupu je nějaký text místo čísla)? Ano, funkce scanf vrací počet úspěšných konverzí jako svou funkční (návratovou) hodnotu. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 18/46
Funkce scanf časté otázky Jak funkce scanf pracuje za specifických podmínek: Co se stane, když zavolám funkci scanf na konci souboru (tzn. není už co číst - end-of-file)?. Funkce jednoduše skončí se čtením proměnných a vrátí počet úspěšných konverzí. Ten je ovšem menší, než bylo požadováno. Konec vstupu je signalizován nejen pro diskové soubory (přečtením posledního znaku), ale i při vstupu z klávesnice, a to stiskem Ctrl-D (UNIX) / Ctrl-Z (Win). Přeskočí funkce scanf chybné znaky (např. text, když se očekává číslo) ze vstupu? Když funkce scanf nemůže zkonvertovat vstupní znaky do předepsaného datového typu, nepřeskočí tyto znaky na vstupu. Čtení skončí na prvním znaku, který do znakové podoby dané konverzí nepatří. Toto chování může vést k nekonečnému cyklu (zacyklení), pokud funkce scanf není použita korektně. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 19/46
Funkce scanf ošetření chyb... /* obsluha bankomatu */ int balance, x;... balance =...;... /* balance obsahuje zůstatek na účtu */ printf ( "Zadejte castku pro vyber:\n"); scanf ( "%d", &x );... /* vydat peníze - celkem x */ balance -= x; printf ( "Novy zustatek: %d\n", balance ); M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 20/46
Funkce scanf ošetření chyb... /* obsluha bankomatu */ int balance, x;... balance =...;... /* balance obsahuje zůstatek na účtu */ printf ( "Zadejte castku pro vyber:\n"); scanf ( "%d", &x );... /* vydat peníze - celkem x */ balance -= x; printf ( "Novy zustatek: %d\n", balance ); Co když bude výběr větší než zůstatek? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 20/46
Funkce scanf ošetření chyb... /* obsluha bankomatu */ int balance, x;... balance =...;... /* balance obsahuje zůstatek na účtu */ printf ( "Zadejte castku pro vyber:\n"); scanf ( "%d", &x );... /* vydat peníze - celkem x */ balance -= x; printf ( "Novy zustatek: %d\n", balance ); Co když bude výběr větší než zůstatek? Co když budeme vybírat zápornou částku? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 20/46
Funkce scanf ošetření chyb... /* obsluha bankomatu */ int balance, x;... balance =...;... /* balance obsahuje zůstatek na účtu */ printf ( "Zadejte castku pro vyber:\n"); scanf ( "%d", &x );... /* vydat peníze - celkem x */ balance -= x; printf ( "Novy zustatek: %d\n", balance ); Co když bude výběr větší než zůstatek? Co když budeme vybírat zápornou částku? Co když se uživatel při zadávání splete (nečíselný vstup)? M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 20/46
Funkce scanf ošetření chyb... /* obsluha bankomatu */ int balance, x;... /* balance obsahuje zůstatek na účtu */ printf ( "Zadejte castku pro vyber:\n"); if ( scanf ( "%d", &x )!= 1 x <= 0 x > balance ) {... /* upozornění na chybu, oprava zadaní */ } else {... /* vydat peníze - celkem x */ balance -= x; printf ( "Novy zustatek: %d\n", balance ); } M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 21/46
Funkce scanf #include <stdio.h> int main ( void ) { int x, y; printf("vstup souradnic:\n"); while ( scanf( "%d %d", &x, &y )!= 2 ) { /* Konverze se nezdařila */ printf ( "Spatny vstup. Prosim zopakovat.\n" ); } /* oops - nekonečný cyklus při špatném vstupu */ printf("souradnice jsou (%d,%d)\n", x, y ); return 0; } M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 22/46
Funkce scanf oprava #include <stdio.h> int main ( void ) { int x, y; printf("vstup souradnic:\n"); while ( scanf( "%d %d", &x, &y )!= 2 ) { /* Konverze se nezdařila */ printf ( "Spatny vstup. Prosim zopakovat.\n" ); /* Odstranit ze vstupu chybně zadané znaky */ /* (cyklus a funkce fgetc) */ } /* ok, data načtena správně */ printf("souradnice jsou (%d,%d)\n", x, y ); return 0; } M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 23/46
Kontrola vstupů Programy potřebují mít jistotu, že pracují s platnými daty. Dnes běžné zranitelnosti (buffer overflow, code injection, XSS,... ) jsou speciální případy neošetřených vstupů. Neošetřené vstupy ročně stojí miliardy dolarů. Ošetřování vstupů je nudné a pracné. Přesto si zvykněte psát programy tak, aby vždy kontrolovaly správnost vstupu. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 24/46
Kontrola vstupů Programy potřebují mít jistotu, že pracují s platnými daty. Dnes běžné zranitelnosti (buffer overflow, code injection, XSS,... ) jsou speciální případy neošetřených vstupů. Neošetřené vstupy ročně stojí miliardy dolarů. Ošetřování vstupů je nudné a pracné. Přesto si zvykněte psát programy tak, aby vždy kontrolovaly správnost vstupu. Na slidech budeme ošetření vstupů vynechávat. Důvodem je omezený prostor slide. Při ostatních příležitostech (programy na proseminářích, cvičeních,... ) ošetření vstupů nevynecháme. Vaše programy budeme kontrolovat, zda ošetřují nesprávné vstupy. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 24/46
Kontrola vstupů (de)motivace Za obrázek děkujeme Randallu Munroe, XKCD comics #327 (xkcd.com). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 25/46
Celočíselné datové typy v C Jméno alternativní jména B min max char signed char 1 128 127 unsigned char 1 0 255 short short int 2 32768 32767 signed short signed short int unsigned short unsigned short int 2 0 65535 int signed 4 2 31 2 31 1 signed int unsigned unsigned int 4 0 2 32 1 long long int 4 2 31 2 31 1 signed long signed long int unsigned long unsigned long int 4 0 2 32 1 Poznámka: tabulka shrnuje celočíselné typy a jejich vlastnosti tak, jak jsou obvykle definovány v dvojkovém doplňku pro reprezentaci záporných čísel. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 26/46
Celočíselné datové typy v C Pamět ová reprezentace a rozsahy standardních datových typů nejsou v normě jazyka C definovány. Místo definice v normě jsou reprezentace a rozsahy dány implementací. Proč? Rozsahy dat jsou přístupné programátorovi ve standardních hlavičkových souborech (limits.h, float.h) např. INT MAX, INT BITS,... Norma jazyka C zaručuje pouze: sizeof(short int) <= sizeof(int) <= sizeof(long int) Některé kompilátory zavádějí vlastní celočíselné datové typy: long long 64 bitové celé číslo, v gcc/g++, int8,..., int64 8/16/32/64 bitová celá čísla v MSVC. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 27/46
Celočíselné datové typy v C Celočíselné literály: dekadický: 123, 45678, šestnáctkový: 0x123Ab, 0X569Fd (na začátku je 0x nebo 0X), osmičkový: 0123, 0765 (na začátku je 0), bez znaménka: 1234u, 5678U, long: 1234567679l, unsigned long: 87654321lu, long long (gcc): 1234567890123456LL, 0x12345LLu, int64 (MSVC): 1234567890123456i64, 0x12345ui64, numerické literály jsou považovány za signed int, není-li použita přípona. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 28/46
Celočíselné datové typy vnitřní reprezentace Hodnoty bez znaménka jsou uloženy v binárním kódu, datové typy delší než 8 bitů zaujímají několik bajtů za sebou, pořadí bajtů: little-endian (lohi, Intel), big-endian (hilo, Motorola). /* předpokládáme 32-bitová celá čísla */ unsigned int a = 1000; 1000 = 0x3e8 = 0011 1110 1000 (bin) počítač s little-endian: 1110 1000 0000 0011 0000 0000 0000 0000 e8 03 00 00 počítač s big-endian: 0000 0000 0000 0000 0000 0011 1110 1000 00 00 03 e8 M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 29/46
Celočíselné datové typy vnitřní reprezentace Hodnoty se znaménkem musí nějak znaménko obsahovat je třeba použít vhodný kód, Nejobvyklejší je dvojkový doplněk, jiné kódy: jednotkový doplněk, posunutá nula, znaménko a absolutní hodnota,... Jak dvojkový doplněk pracuje? Je-li je hodnota kladná nebo nulová: hodnota je v binárním kódu, binární kód je výsledek. Je-li hodnota záporná: vezme se binární kód absolutní hodnoty, znegují se všechny bity, k tomuto číslu se přičte 1. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 30/46
Celočíselné datové typy vnitřní reprezentace /* předpokládáme 8-bitovou hodnotu */ signed char x = 53; 53 >= 0, 53 = 0x35 = 0011 0101 (bin) dvojkový doplněk 53: 0011 0101 (bin) signed char x = -45; -45 < 0, pro výpočet použijeme abs(-45): 45 = 0x2d = 0010 1101 (bin) negace bitů: 1101 0010 (bin) přičtení 1: +1 dvojkový doplněk -45: 1101 0011 (bin) M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 31/46
Celočíselné datové typy vnitřní reprezentace Dvojkový doplněk x je: 0101 1011 (bin). Jaká je hodnota x? Bit nejvíce vlevo (nejvýznamnější bit) je 0: x >= 0. 0101 1011 (bin) = 0x5b = 91 (dec). x = 91 Dvojkový doplněk x je: 1101 1100 (bin). Jaká je hodnota x? Nejvýznamnější bit je 1: x < 0. negace bitů reprezentace: 0010 0011 (bin) přičtení 1: +1 absolutní hodnota x: 0010 0100 (bin) x = - 0010 0100 (bin) = - 0x24 = -36 (dec) M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 32/46
Celočíselné datové typy výstupní konverze #include <stdio.h> int main ( void ) { int x = -1; } printf ( "x = %d (signed,dec)\n", x ); printf ( "x = %i (signed,dec)\n", x ); printf ( "x = %u (unsigned,dec)\n", x ); printf ( "x = %x (unsigned,hex)\n", x ); printf ( "x = %X (unsigned,hex)\n", x ); printf ( "x = %o (unsigned,oct)\n", x ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 33/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d x = -1 (signed,dec) %i M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d x = -1 (signed,dec) %i x = -1 (signed,dec) %u M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d x = -1 (signed,dec) %i x = -1 (signed,dec) %u x = 4294967295 (unsigned,dec) %x M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d x = -1 (signed,dec) %i x = -1 (signed,dec) %u x = 4294967295 (unsigned,dec) %x x = ffffffff (unsigned,hex) %X M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d x = -1 (signed,dec) %i x = -1 (signed,dec) %u x = 4294967295 (unsigned,dec) %x x = ffffffff (unsigned,hex) %X x = FFFFFFFF (unsigned,hex) %o M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy výstupní konverze Program zobrazí: %d x = -1 (signed,dec) %i x = -1 (signed,dec) %u x = 4294967295 (unsigned,dec) %x x = ffffffff (unsigned,hex) %X x = FFFFFFFF (unsigned,hex) %o x = 37777777777 (unsigned,oct) M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 34/46
Celočíselné datové typy více o přiřazení Na rozdíl od jazyka Ada lze do celočíselné proměnné přiřadit i hodnotu odlišného typu. Když je neceločíselná hodnota (např. hodnota v pohyblivé řádové čárce) přiřazena celočíselné proměnné, je hodnota před přiřazením zkonvertována na celé číslo (tzn. desetinná část je odseknuta). Mohou nastat tři různé případy přiřazení celočíselné hodnoty celočíselné proměnné: sizeof(var) = sizeof(value) binární reprezentace je jednoduše zkopírována, sizeof(var) < sizeof(value) vyšší bajty navíc jsou ztraceny, nižší zkopírovány, sizeof(var) > sizeof(value) hodnota je rozšířena o vyšší bajty tak, aby vyplnila celou proměnnou. Předchozí pravidla jsou rozumná, avšak výsledky mohou být překvapující. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 35/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; printf ( "ux = %u, x = %d\n", ux, x ); y = uy; printf ( "uy = %u, y = %d\n", uy, y ); } ux = -100; printf ( "ux = %u\n", ux ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; printf ( "ux = %u, x = %d\n", ux, x ); /* ux = 1000, x = 1000 */ y = uy; printf ( "uy = %u, y = %d\n", uy, y ); } ux = -100; printf ( "ux = %u\n", ux ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; /* 00...001111101000 */ printf ( "ux = %u, x = %d\n", ux, x ); /* ux = 1000, x = 1000 */ y = uy; printf ( "uy = %u, y = %d\n", uy, y ); } ux = -100; printf ( "ux = %u\n", ux ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; /* 00...001111101000 */ printf ( "ux = %u, x = %d\n", ux, x ); /* ux = 1000, x = 1000 */ } y = uy; printf ( "uy = %u, y = %d\n", uy, y ); /* uy = 4294967295, y = -1 */ ux = -100; printf ( "ux = %u\n", ux ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; /* 00...001111101000 */ printf ( "ux = %u, x = %d\n", ux, x ); /* ux = 1000, x = 1000 */ } y = uy; /* 11...111111111111 */ printf ( "uy = %u, y = %d\n", uy, y ); /* uy = 4294967295, y = -1 */ ux = -100; printf ( "ux = %u\n", ux ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; /* 00...001111101000 */ printf ( "ux = %u, x = %d\n", ux, x ); /* ux = 1000, x = 1000 */ } y = uy; /* 11...111111111111 */ printf ( "uy = %u, y = %d\n", uy, y ); /* uy = 4294967295, y = -1 */ ux = -100; printf ( "ux = %u\n", ux ); /* ux = 4294967196 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y; unsigned int ux = 1000, uy = 0xffffffff; /* stejný počet bajtů - int, unsigned int */ x = ux; /* 00...001111101000 */ printf ( "ux = %u, x = %d\n", ux, x ); /* ux = 1000, x = 1000 */ } y = uy; /* 11...111111111111 */ printf ( "uy = %u, y = %d\n", uy, y ); /* uy = 4294967295, y = -1 */ ux = -100; /* 11...111110011100 */ printf ( "ux = %u\n", ux ); /* ux = 4294967196 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 36/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x = 1000, y = 767; signed char cx, cy; /* char je kratší než int */ cx = x; printf ( "x = %d, cx = %d\n", x, cx ); cy = y; printf ( "y = %d, cy = %d\n", y, cy ); } return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 37/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x = 1000, y = 767; signed char cx, cy; /* char je kratší než int */ cx = x; printf ( "x = %d, cx = %d\n", x, cx ); /* x = 1000, cx = -24 */ cy = y; printf ( "y = %d, cy = %d\n", y, cy ); } return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 37/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x = 1000, y = 767; signed char cx, cy; /* char je kratší než int */ cx = x; /* 11101000 <- 00...001111101000 */ printf ( "x = %d, cx = %d\n", x, cx ); /* x = 1000, cx = -24 */ cy = y; printf ( "y = %d, cy = %d\n", y, cy ); } return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 37/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x = 1000, y = 767; signed char cx, cy; } /* char je kratší než int */ cx = x; /* 11101000 <- 00...001111101000 */ printf ( "x = %d, cx = %d\n", x, cx ); /* x = 1000, cx = -24 */ cy = y; printf ( "y = %d, cy = %d\n", y, cy ); /* y = 767, cy = -1 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 37/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x = 1000, y = 767; signed char cx, cy; } /* char je kratší než int */ cx = x; /* 11101000 <- 00...001111101000 */ printf ( "x = %d, cx = %d\n", x, cx ); /* x = 1000, cx = -24 */ cy = y; /* 11111111 <- 00...001011111111 */ printf ( "y = %d, cy = %d\n", y, cy ); /* y = 767, cy = -1 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 37/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; printf ( "x = %d\n", x); y = cy; printf ( "y = %d\n", y); cz = z; z = cz; printf ( "z = %d\n", z); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; printf ( "x = %d\n", x); /* x = 128 */ y = cy; printf ( "y = %d\n", y); cz = z; z = cz; printf ( "z = %d\n", z); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; /* 00...000010000000 <- 10000000 */ printf ( "x = %d\n", x); /* x = 128 */ y = cy; printf ( "y = %d\n", y); cz = z; z = cz; printf ( "z = %d\n", z); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; /* 00...000010000000 <- 10000000 */ printf ( "x = %d\n", x); /* x = 128 */ y = cy; printf ( "y = %d\n", y); /* y = -10 */ cz = z; z = cz; printf ( "z = %d\n", z); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; /* 00...000010000000 <- 10000000 */ printf ( "x = %d\n", x); /* x = 128 */ y = cy; /* 11...111111110110 <- 11110110 */ printf ( "y = %d\n", y); /* y = -10 */ cz = z; z = cz; printf ( "z = %d\n", z); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; /* 00...000010000000 <- 10000000 */ printf ( "x = %d\n", x); /* x = 128 */ y = cy; /* 11...111111110110 <- 11110110 */ printf ( "y = %d\n", y); /* y = -10 */ cz = z; z = cz; printf ( "z = %d\n", z); /* z = -128 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; /* 00...000010000000 <- 10000000 */ printf ( "x = %d\n", x); /* x = 128 */ y = cy; /* 11...111111110110 <- 11110110 */ printf ( "y = %d\n", y); /* y = -10 */ cz = z; /* 10000000 <- 00...000010000000 */ z = cz; printf ( "z = %d\n", z); /* z = -128 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy více o přiřazení #include <stdio.h> int main ( void ) { int x, y, z = 128; unsigned char cx = 128; signed char cy = -10, cz; } x = cx; /* 00...000010000000 <- 10000000 */ printf ( "x = %d\n", x); /* x = 128 */ y = cy; /* 11...111111110110 <- 11110110 */ printf ( "y = %d\n", y); /* y = -10 */ cz = z; /* 10000000 <- 00...000010000000 */ z = cz; /* 11...111110000000 <- 10000000 */ printf ( "z = %d\n", z); /* z = -128 */ return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 38/46
Celočíselné datové typy (de)motivace If androids some day DO dream of electric sheep, do not forget to declare sheepcount as a long int. Za obrázek děkujeme Randallu Munroe, XKCD comics #571 (xkcd.com). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 39/46
Znakový datový typ (char) Znaky jsou kódovány jako čísla. Jsou používány různé standardy pro kódování znaků: ASCII (7 bit), 128 kódů, pouze pro anglickou množinu znaků, ASCII extended (8 bit), horních 128 kódů je použito pro národní znaky (ISO-8859-1 až ISO-8859-15, kódové stránky Windows 1250/1251/1252,... ), UNICODE (až 2 20 + 2 16 znaků), různé kódování do bajtů (UTF-8, UTF-16, UTF-32, UCS2, UCS4), EBCDIC (8 bitů, velké počítače IBM). Originální 7-bitový kód ASCII je společný pro všechny kódy (s výjimkou EBCDIC): 0 31 řídící kódy (jako \n nový řádek, ASCII 0x0A), 32 mezera (0x20), 33 127 symboly, číslice, písmena (anglická abeceda), 48 57 digits 0 9 (0x30 0x39), 65 90 písmena A Z (0x41 0x5a), 97 122 písmena a z (0x61 0x7a). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 40/46
Znakové literály Jednoduché znaky znak mezi apostrofy: a, *, 1,... Na rozdíl od PHP, jazyky C/C++/Java rozlišují: znaky (právě jediný znak), v apostrofech, řetězce (žádný nebo více znaků), v uvozovkách. Netisknutelné znaky se zapíší pomocí tzv. escape sekvencí: \12 (oktalově 012 = 10 (dekadicky) = LF), \xa (hexadecimálně 0xA = 10 (dekadicky) = LF). Zkrácené escape sekvence pro často používané znaky: \n (LF = 0x0A), \t (TAB = 0x09), \ (apostrof = 0x27), \" (uvozovky = 0x22), \\ (zpětné lomítko = 0x5c). M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 41/46
Znakový vstup a výstup Funkce printf a scanf používají znakovou konverzi %c. printf vypíše jeden znak, který je dán odpovídajícím parametrem. Funkce scanf přečte ze vstupu jeden znak, jehož kód uloží do proměnné typu char. Funkce scanf přeskočí bílé znaky (mezery, tabelátory, nové řádky). Funkce scanf nemůže být použita pro čtení těchto znaků (v tomto případě je třeba použít funkci getc). Poznamenejme, že C/C++ nerozlišuje znaky (typu char) a malá celá čísla (opět typu char). Vnitřní reprezentace a výpočty jsou stejné, jen vstup a výstup je jiný. M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 42/46
Příklad znakového vstupu a výstupu #include <stdio.h> int main ( void ) { char c; } printf ( "Napis znak:\n" ); scanf ( "%c", &c ); printf ( "Napsal jsi: %c, code %d\n ", c, c ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 43/46
Znakový vstup a výstup #include <stdio.h> int main ( void ) { char c = @ ; int i = 0x40; unsigned int u = 0xff40; } printf ( "c = %x %d %c\n ", c, c, c ); printf ( "i = %x %d %c\n ", i, i, i ); printf ( "u = %x %d %c\n ", u, u, u ); return 0; M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 44/46
Znakový vstup a výstup Výstup programu: c = M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 45/46
Znakový vstup a výstup Výstup programu: c = i = 40 64 @ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 45/46
Znakový vstup a výstup Výstup programu: c = i = u = 40 64 @ 40 64 @ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 45/46
Znakový vstup a výstup Výstup programu: c = i = u = 40 64 @ 40 64 @ ff40 65344 @ M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 45/46
Otázky a odpovědi Otázky... M. Baĺık, L. Vagner a J. Vogel, ČVUT FIT Proměnné, I/O, BI-PA1 46/46