13.4.2010 Typová konverze - změna jednoho datového typu na jiný - známe dva základní implicitní ("sama od sebe") a explicitní (výslovně vyžádána programátorem) - C je málo přísné na typové kontroly = dokáže často datové typy přizpůsobit (C je jazyk se slabou typovou kontrolou) - výhoda volnost pro programátora (hlavně v nízkoúrovňovém programování) - nevýhoda přílišná volnost může k nepříjemným chybám (projeví se při programování aplikací na vyšší úrovni - win) Implicitní d = 3; /* implicitní typová konverze int => double */ d = 3 * 2.5; (pozn. zobrazení int v paměti se musí převést na zobrazení double čísla v paměti viz přednáška č.2) - "priorita" konverzí aneb co se konvertuje na co (které typy jsou vyšší) v případě, že se někde "potkají" dva datové typy (při matemat. operacích apod.): int => unsigned int => long => unsigned long => float => double => long double - tj. bude-li: float a; double b, c; c = a + b; - a se bude konvertovat na double a pak se provede součet, výsledek součtu bude typu double
- pokus se někde vyskytne typ char nebo short int, automaticky se konvertují na int, např.: int c; /* vetsinou znaky */ c++; c = 'A' + 3; Pozor na konverze u typů signed a unsigned: unsigned char uc; signed char sc; uc = 0; /* nejmenší */ uc = 255; /* největší */ sc = -128; /* nejmenší */ sc = 127; /* největší */ sc = 255; /* v sc bude -1 */ sc = 127; sc = sc + 1; /* v sc bude -128 */ Pozn. vzpomeňte na starší programy, které u velkého disku hlásí: Zbývá -1525276 Bytů. Explicitní - přímo ji požadujeme pomocí operátoru přetypování: (datový_typ) prom (datový_typ) konstanta - používá se hlavně když nuceně a záměrně konvertuji nějaký vyšší typ na nižší (např. double na int) tj. když dochází k nějakému omezení rozsahu, přesnosti atp. Např.: int i; double d = 3.14; i = (int) d; /* i bude 3, d bude stále 3.14 */ (pozn. d se samozřejmě nemění, nic s ním nedělám) char c;
c = (char) i; - (double), (float) atd. na stejném principu - přetypování má vysokou prioritu i = (int) d * 5; /* napřed se provede (int) d a potom nás.*/ - jinak pouze pomocí závorek: i = (int) (d * 5); /* zde se napřed vynásobí, potom konv.*/
Pozor, připomínka ze začátku semestru: double PI = 3.14159; d = 4 / 3 * PI; /* int / int celočíselné dělení s výsledkem 1 */ - d bude PI, tj. 3.14159 Správně např. s explicitní typovou konverzí: double PI = 3.14159; d = (double) 4 / (double) 3 * PI; - d bude PI, tj. 5,1887866666666666666666666666667 - nebo bez konverze rovnou a lépe: double PI = 3.14159; d = 4.0 / 3.0 * PI; Speciální případ přetypování na typ void - void - prázdný typ, někdy obecný typ Užití např.: - potlačení návratové hodnoty funkce (void) sin(pi); /* poněkud málo užitečné použití ;-) */ - v případě pointerů (probereme později) ukazatelů na proměnnou, je to proměnná obsahující adresu jiné proměnné, musí se dělat na konkrétní datový typ: int *p_i; /* p_i bude obsahovat adresu proměnné typu int */ void *p_cokoliv; /* pointer na jakýkoliv typ, univerzální pointer */ - při použití je nutno potom přetypovat na konkrétní datový typ. int i; p_cokoliv = (void *) &i;
p_i = (int *) p_cokoliv; - vícenásobné přetypování zde použito na odříznutí desetinných míst d = 13.628346; d = (double)((long int) d); /* d bude 13.0 */ - pozor, aby se double číslo po konverzi na např. int, do tohoto typu "vešlo", aby nebylo moc velké Např. udělat test typu: if (d > (double) INT_MAX) (pro minimum je konstanta INT_MIN) pozor názvy konstant se mohou lišit dle překladače (nutno naincludovat limits.h) (int) f = 3; /*fuj! nelze, přetypování NENÍ l-hodnota */
Preprocesor jazyka C - direktivy začínají # - zpracují před vlastním překladem do stroj. kódu - např. #include Konstanty - pomocí direktiv - název konstanty obvykle velkými písmeny - překladač (preprocesor) před překladem projde zdrojový kód a nahradí všechny výskyty názvu konstanty její hodnotou (jako funkce Najít a nahradit ve Wordu atp.) #define PI 3.14 #define PIPI (PI + PI) /* zde jsou závorky NUTNÉ!!! */ main() { d = 2.0 * PIPI; /* bez závorek u PIPI by počítal: 2 * 3.14 + 3.14 */ printf("\nd = %f\n", d); system("pause"); - zrušení definice: #undef PI
Lze též konstantu definovanou, ale s neurčenou hodnotou: #define WOKNA main() { d = 2 * PIPI; printf("\nd = %f\n", d); #ifdef WOKNA printf("\njsem pod Woknama... UAAAA!!!\n"); #else Tady dam cokoliv, sem se prekladac nedostane!!! asdf printf("\nnejsem pod Woknousama, huraaa...\n"); #endif - pozor příkazy s # jsou directivy, nikoli příkazy jazyka C, tj. říkají ne kudy program běží (třeba onen ifdef), ale co se překládá a co ne. lze též: #ifndef WOKNA - zbytek je stejný Nebo: #define WIN 2000 main() { d = 2 * PIPI; printf("\nd = %f\n", d); - tj. if not def - jestliže není def. #if WIN == 2000 printf("\njsem pod Woknama 2000... UAAAA!!!\n"); #else
Tady dam cokoliv, sem se prekladac nedostane!!! asdf printf("\nnejsem pod Woknousama, huraaa...\n"); #endif - konstanty nemusí jen číselné, lze znaky, řetězce a též operátory: #define MOD % - potom místo a % b lze používat a MOD b #define KONEC_RADKU '\n' - nebo i vypočtené hodnoty: #define POSUN ('a' - 'A') Makra - dělají se také pomocí #define - podobné (použitím) funkcím - předpřipravená jsou např. v ctype.h - jak na vlastní makro: #define je_velke(c) ((c) >= 'A' && (c) <='Z') - a potom použití v programu: if (je_velke('a' + 'B')) {.. - před překladem z toho preprocesor udělá toto: if ((('A' + 'B') >= 'A' && ('A' + 'B') <='Z')) {.. - opět je nutno závorkovat jak tělo makra, tak jeho parametr uvnitř těla
Makra v ctype.h např.: isalnum(c) je číslo nebo písmeno? isalpha(c) je písmeno? isascii(c) je ascii 0-127? iscntrl(c) je ascii 0-26? např. test jen na tisknutelné znaky bez háčků a čárek: if (isascii(c) &&!iscntrl(c)) { putchar(c); isdigit(c) je číslice? islower(c) je malé písmeno? isupper(c) je velké písmeno? isprint(c) je ascii 32-126 (tisknutelné)? ispunct(c) je interpunkční znaménko? (,. / atp.) isspace(c) je mezera, tab, \n tj. nový řádek? isxdigit(c) je hexadec. cislice (0-9, A-F, a-f)? isgraph(c) je ascii 33-126 (i pseudografické znaky)? Konverzní makra tolower(c) - na malá písmena toupper(c) - na velká písmena toascii(c) - ořízne bit s pořadím 7 (tj. osmý, nejvyšší bit), tj. z 8 bitů znaku bere jen dolních 7, tj. 0. až 7. Pole stručný úvod do začátku, podrobně později - statická pole (ne dynamicky) - číslují se od 0 int policko[100]; // tj. pole je od 0 do 99!!! policko[5] = 7; // pozor je to 6. prvek s indexem 5
policko[99] = 2; // poslední prvek. policko[100] = 78; // C nijak neprotestuje příkaz vykoná - hodnota 78 je zapsána do paměti ZA moje pole, přepisuji paměť, kterou nemám přidělenu => pravděpodobně bude program chybovat. Může tam uložena moje jiná proměnná... - to znamená, že C nekontroluje rozsahy polí a ohlídání je na programátorovi musím si udržovat např. nějakou proměnnou, kde budu délku pole uloženu.