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í double d; 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 nás.*/
a potom
- 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 d; 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 d; double PI = 3.14159; d = (double) 4 / (double) 3 * PI; - d bude PI, tj. 5,1887866666666666666666666666667
- nebo bez konverze rovnou a lépe: double d; 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 double d; 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() { double d; 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() { double d; 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
- tj. if not def - jestliže není def.
- zbytek je stejný Nebo: #define WIN 2000 main() { double d; d = 2 * PIPI; printf("\nd = %f\n", d); #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
#define KONEC_RADKU
MOD b
'\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); }
– 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) ? isdigit(c)
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.