270 likes | 339 Views
10. přednáška 10. 4. 2008 - soubory (soubory na elementární úrovni) - projekty - správa paměti (16 bitové prostředí) - výstupy na monitor (práce s barvami, 16 bitové prostředí) Studijní materiály najdete na adrese: http://www.uai.fme.vutbr.cz/~vdumek/.
E N D
10. přednáška • 10. 4. 2008 • - soubory (soubory na elementární úrovni) • - projekty • - správa paměti (16 bitové prostředí) • - výstupy na monitor (práce s barvami, 16 bitové prostředí) • Studijní materiály najdete na adrese: • http://www.uai.fme.vutbr.cz/~vdumek/
#include <stdio.h> #include <stdio.h> long filesize(FILE *stream); int main(void) { int main(void) FILE *stream; { /* otevri pro cteni */ FILE *stream; stream = fopen(“DUMMY.FIL”, “r”); stream = fopen(“MY.TXT”,”w+”); /* cti ze souboru */ fprintf(stream, “toto je test”); fgetc(stream); printf(“velikost: %ld”, filesize(stream)); /* kontrola na EOF */ fclose(stream); if(feof(stream)) return(0); printf(“konec souboru\n”); } /* zavri soubor */ fclose (stream); return(0); } long filesize(FILE *stream) { length = ftell(stream); long curpos, length; fseek(stream, curpos, SEEK_SET); return length; curpos = ftell(stream); } fseek(stream, 0L, SEEK_END);
Soubory na elementární úrovni - deklarace funkcí elementárního přístupu jsou v IO.H, nelze spoléhat na přenositelnost int creat(const char *jm_soub, int povolen) - pokud soubor s daným jménem existuje, bude přepsán, parametr povolen má smysl pouze pro nové soubory, pokud soubor již existuje a je nastaven pro čtení, volání neuspěje a soubor zůstane nezmě- něný pokud je parametr pro zápis, bude soubor zkrácen na nulovou délku Možné hodnoty parametru povolen (SYS.H, STAT.H): S_IWRITE povolen zápis S_IREAD povoleno čtení S_IREAD | S_IWRITE povoleno čtení a zápis Vytvoření souboru
Pro téměř všechny OS platí, že pokud je povolen zápis, je povo- leno i čtení. Režim souboru je dán globální proměnnou _fmode (O_TEXT, O_BINARY). Při úspěšném otevření se vrací symbo- lické číslo (>4), jinak se vrací hodnota -1 a je nastavena globální chybová proměnná errno na některou z následujících hodnot: ENOENT jméno souboru nenalezeno EMFILE příliš mnoho souborů EACCES přístup se nepovoluje Prototyp v hlavičce FCNTL.H int open(const char *jm_cest, int pristup) Přístup se konstruuje po bitech jako logický součet příznaků: Otevření souboru
PříznakVýznam O_RDONLY Pro čtení lze použít pouze O_WRONLY Pro zápis jeden příznak O_RDWR Zápis, čtení PříznakVýznam O_NDELAY pro komp. s UNIX O_APPEND Před každým zápisem se ukazatel souboru nastaví na konec O_CREAT Pokud soubor existuje, nemá příznak smysl O_TRUNC Existující soubor se zkrátí na nulu O_EXCL pro komp. s UNIX O_BINARY Binární režim O_TEXT Textový režim U těchto příznaků lze použít libovolnou kombinaci
Při úspěšném otevření se vrací nezáporné celé číslo, ukazatel souboru se nastaví na počátek. Při chybě se vrací -1 a je nasta- vena proměnná errno. int close(int cis_soub) funkce, IO.H, návratová hodnota při úspěš- ném zavření je 0, při neúspěchu -1 při současném nastavení pro- měnné errno (špatné číslo souboru). #include <stdio.h> handle = creat(“DU.FIL”, S_IREAD | #include <string.h> S_IWRITE); #include <fcntl.h> /* pis 10 slabik do souboru */ #include <io.h> write(handle, buf, strlen(buf)); /* zavri soubor */ int main(void) close(handle) { } int handle; char buf[11] = “0123456789”; /* změna default modu textoveho na binarni */ _fmode = O_BINARY; /* vytvor soubor pro cteni a zapis */ Zavření souboru
Čtení a zápis do elementárního souboru int write(int cis_soub, void *blk, int poc_slabik); int read(int cis_soub, void *blk, unsigned poc_slabik); Vyrovnávací paměť, na kterou ukazuje blkje zapsána funkcí write() do souboru se symbolickým číslem cis_soub. Počet slabik, který je zapsán do souboru nebude nikdy větší, než poc_slabik, vyjma zápisu do textových souborů. Pokud je zap- saný počet slabik menší než požadovaný, došlo k chybě (vrací se -1). Automaticky přidané znaky CR se nepočítají. Funkce read() se pokouší číst počet slabik poc_slabik ze souboru sdruženého se symbolickým číslem cis_soub do vyrovnávací paměti blk. Při čtení se vrací přečtený počet bytů, při textovém režimu se odstraňuje znak CR, při znaku CTRL-Z čtení končí. Znaky CTRL-Z a CR se nepočítají.
Maximální počet slabik, které lze přečíst je 65534, neboť 65535 je 0xFFFF (hodnota -1 - chyba). Při zjištění konce souboru je návratová hodnota 0. #include <stdio.h> #include <io.h> int main(void) { void *buf; int handle, bytes; buf = malloc(10); /* hleda soubor a pokousi se cist 10 byte */ if((handle = open(“test.$$$”, O_RDONLY|O_BINARY, S_IWRITE|S_IREAD)) == -1) { printf(“chyba otevreni\n”); exit(1); } if((bytes = read(handle, buf, 10) == -1)
{ printf(“spatne cteni\n“); exit(1); } else printf(“cteni: %d slabik precteno\n“, bytes); return(0); } #include <stdio.h> #include <io.h> int main(void) { int handle, length, res; char string[40]; /* vytvori soubor a zapise do nej string, pokud soubor existuje, bude prepsan */ if((handle = open(“test.$$$“, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) == -1 { printf(“chyba otevreni\n“); exit(1); }
strcpy(string, “nazdar studente\n“); length = strlen(string); if((res = write(handle, string, length)) != length) { printf(“chyba zapisu do souboru\n“); exit(1); } printf(“zapsano %d slabik do souboru\n“, res); close(handle); return(0); } FILE *fdopen(int cis_soub, char *typ) Při sdružení elementárního souboru se streamem musí být typ proudu shodný s režimem souboru s číslem cis_soub. int fileno(FILE *dat_pr) Pokud má stream více symbolických čísel, vrací fileno() to číslo, které bylo proudu přiřazeno při prvním otevření, pro práci se soubory na elementární úrovni není nabídka funkcí a maker tak bohatá, jako pro práci se streamy. Spojení souborů na elementární úrovni s proudy dat
/* demonstrace funkce fdopen */ #include <stdio.h> #include <io.h> int main(void) { int cis_soub, stav; FILE *proud; /* otevri soubor */ cis_soub = open(”muj1.txt”, O_CREAT); /* a predelej ho na proud dat */ proud = fdopen(cis_soub, ”w”); if(proud == NULL) printf(”vsechno spatne\n”); else { /* pisi do nej pomoci funkce pro stream */ fprintf(proud, “ja jsem predelany soubor”); fclose(proud); } }
void main(void) { FILE *sou1, *sou2, *sou3, *a, *b, *c; int han1, han2, han3; sou1 = fopen(“tmp1.txt”, “w+”); han1 = fileno(sou1); sou2 = fopen(“tmp2.txt”, “w+”); han2 = fileno(sou2); sou3 = fopen(“tmp3.txt”, “w+”); han3 = fileno(sou3); fprintf(sou1, “nazev souboru\tsymb.c.\tukazatel na FILE\n”); fprintf(sou1, “\t\t\t(han1-3)\t\t(sou1-3)\n”); fprintf(sou1, “++++++++++++++++++++++++++++++++++”); fprintf(sou1, “tmp1.txt\t\t%d\t\t\t%p\n”, han1, sou1); fprintf(sou1, “tmp2.txt\t\t%d\t\t\t%p\n”, han2, sou3); fprintf(sou1, “tmp3.txt\t\t%d\t\t\t%p\n”, han3, sou3); fcloseall() } nazev souboru symb.c. ukazatel na FILE (han1-3) (sou1-3) ++++++++++++++++++++++++++++++++++++++++++++++++++++ tmp1.txt 5 69F9:027E tmp2.txt 6 69F9:0292 tmp3.txt 7 69F9:02A6
Projekty - členění programu do několika modulů, dekompozice programu, udržení délky modulů na přijatelné úrovni, umožnění spolupráce týmu programátorů, zcela v souladu se zásadami SW inženýrství - jak používat symboly v jiných modulech, než ve kterých jsou definované, jak sestavit výsledný program z jednotlivých modulů - dvě fáze vytváření programu: překlad - týká se pouze zpracovávaného modulu, sestavení - odkazy na symboly definované v jiných modulech - některá symbolická označení se mohou vztahovat pouze pro překlad, některá pro sestavování - je nutné, aby měl překladač k dispozici informaci o objektu
Konstanty a makra - řešení pomocí vkládaného modulu (přípona .h je nepovinná) dny.h #define PONDELI 1 a1.c a2.c #define UTERY 2 #include “dny.h” #include “dny.h” #define STREDA 3 …. …. #define CTVRTEK 4 int den; int d2; #define PATEK 5 …. …. #define SOBOTA 6 if(den==PONDELI) d2 = SOBOTA; #define NEDELE 7 { …. } …. Datové typy - typedef, použití pojmenovaných datových typů, vzhledem k typové kontrole opět řešíme pomocí #include dny.h #define PONDELI 1 struct XXX #define UTERY 2 { #define STREDA 3 int a; #define CTVRTEK 4 float b; #define PATEK 5 char c; #define SOBOTA 6 }; #define NEDELE 7
#include “dny.h” #include “dny.h” …. …. struct XXX str1={UTERY, 8.2, “Ahoj”}; int d2; int den; int je_weekend(struct XXX *par) void main(void) { { if(par->a==SOBOTA || par->==…) if(den == PONDELI) return 1; { …. } else } a1.c return 0; a2.c } Funkce - použité funkce musí mít uvedenu deklaraci svého prototypu, ne- musí být uvedeno v modulu, kde je definice hlavicka.h void funkce_1(int); int funkce_2(char*); float fun_a(void); int *fun_b(int, int);
#include “hlavicka.h” #include “hlavicka.h” void main(void) void funkce_1(int x) { { float f: float z; int a, *b; …. f = fun_a(); z = fun_a(); b = fun_b(1, 2); …. a = funkce_2(“ahoj”); } funkce_1(a); } int funkce_2(char *y) { …. } #include “hlavicka.h” float fun_a(void) { …. } int *fun_b(int a, int b) { …. } c2.c c1.c c3.c Proměnné - globální charakter některých dat
- proměnné třídy extern (globální doba života), možnost viditel- nosti i v jiných modulech, definice bývá v jednom modulu, ve zbývajících deklarace float GLOB = 9.9; /* definice s nepovinnou inicializací */ … GLOB *= 6.2; … extern float GLOB; /* deklarace */ … if(GLOB > 1234.5) { … } … B1.C B2.C - při realizaci projektu se obvykle vytváří jeden hlavičkový soubor (deklarace globálních proměnných, definice maker, konstant, datových typů) - problém nastává v okamžiku, kdy potřebujeme vložit modul s deklaracemi globálních proměnných do modulu, ve kterém jsou tyto definovány. Překladač nepovoluje, aby se při překladu souboru objevila současně deklarace i definice - použití podmíněného překladu.
#include "dat.h" … if(GLOB > 1234.5) { … } … #include "dat.h" … GLOB *= 6.2; … float GLOB = 9.9; dat.c extern float GLOB; b2.c dat.h b1.c - při překladu modulu s definicemi globálních dat je potřeba vyřadit část hlavičkového souboru s deklaracemi globálních proměnných #define ANO 1 #define NE 0 struct uiop { char *a; int dotaz; float q; }; void fce1(void); void fce2(struct uiop*); #if !defined DATA extern int promenna_1; extern struct uiop str; #endif #include "hl.h" void fce1(void) { … } void fce2(struct uiop *par) { … } x2.c #include "hl.h" void main(void) { fce2(&str); fce1(); } hl.h x1.c #define DATA #include "hl.h" #undef DATA int promenna_1 = 6; struct uiop str = {"AHOJ", ANO, 3.5}; x3.c
- řízení při sestavování programu přebírá tzv. projekt, skládá se ze zdrojových souborů (.c), relativních modulů (.obj), knihovních modulů (.lib), textový, binární - knihovny lze vytvářet pomocí programu - knihovník, spojení více modulů .obj do jediného souboru (TLIB) Správa paměti (platí pouze pro šestnáctibitové prostředí) Volbou paměťového modelu určujeme mechanismus adresování. Přesahuje-li velikost kódu hranici segmentu, je použit další segment. Platí to i pro data. Tato činnost je v případě programování v assembleru v rukou programátora, u vyšších jazyků je tato činnost dána automaticky volbou paměťového modelu. Touto volbou je určeno, jaké se používají ukazatele jak pro data, tak pro kód. Typy směrníků: near, far, huge. Near - 16 b., používá k výpočtu adresy jeden registr pro offset a segment se bere podle stavu DS nebo CS. Aritmetika funguje bez problémů.
Správa paměti (platí pouze pro šestnáctibitové prostředí) Far - 32 b., obsahuje segmentovou část, takže data, nebo kód mohou mít více segmentů, velikost může přesáhnout velikost 64 KB. S aritmetikou mohou být problémy, neboť pro =, <> se používá 32 b. jako longinteger, nikoliv jako fyzická adresa, ostatní relační operátory používají pouze offset. Při zvyšování far ukazateleo nějakou hodnotu se mění pouze offset (0531:FFFF + 1 = 0531:0000, 0531:0000 - 1 = 0531:FFFF). Pokud chceme ukazatele porovnávat, musíme používat near, nebo huge. Huge - 32b., na rozdíl od vzdálených jsou v normalizovaném tvaru, takže mají co nejvyšší hodnotu segmentové části. Offset potom může být v rozsahu 0-F. Normalizace se provede tak, že po převodu na fyzickou adresu poslední čtyři bity udávají offset, zbytek je segment. 0000 : 0123 -> 0012 : 0003 0040 : 0056 -> 0045 : 0006 500D : 9407 -> 594D : 0007
Správa paměti (platí pouze pro šestnáctibitové prostředí) Z normalizace vyplývá, že ke každé fyzické adrese existuje pouze jeden normalizovaný ukazatel, takže všechny relační operace dávají stejný výsledek. Po každých 16-ti hodnotách se přetáčí jak segmentová část, tak offset, takže se může manipulovat i s daty, přesahujícími 64KB. Za tuto vlastnost se platí pomalejším zpracováním. Drobný (Tiny) - všechny segmentové registry jsou nastaveny na stejnou adresu. Celý program má k dispozici 64KB. Lze jej převést do tvaru .COM. Malý (Small) - kódový a datový segment se liší a vzájemně se nepřesahují, takže k dispozici je 64KB pro kód a 64KB pro data. Používají se near ukazatele. Střední (Medium) - pro kód se používají far, pro data ne, kód může zabírat 1MB, statická data 64KB. Výhodný pro velké programy, které neudržují mnoho dat v paměti. Kompaktní (Compact) - jde o obrácený střední model. Velký (Large) - pro kód i data se používají far ukazatele. Rozsah dat i kódu je 1MB. Statická data jsou max. 64KB. Rozsáhlý (Huge) - i statická data mohou přesahovat více jak 64KB.
kód CS, DS, SS data TINY heap do 64 KB volná paměť SP zásobník
CS sfile sfile A pro každý zdrojový soubor až 64 KB kód sfile B … sfile Z DS, SS data heap MEDIUM do 64 KB volná paměť zásobník SP far heap volná paměť
Výstupy na monitor - textový režim, grafický režim - v textovém režimu je nejmenší ovladatelný element dán počtem znaků na řádek a počtem řádků (80 x 25, 80 x 43, 132 x 100) - na jedné pozici je možné zobrazit znak daný generátorem (volně programovatelný), množina znaků je omezená (256) - pro každou znakovou pozici je určen znak a atribut (způsob zobrazení) - pro každou znakovou pozici jsou ve videopaměti rezervovány dva byty, první pro kód zobrazovaného znaku, druhý pro atribut - možnost přímého zápisu do videopaměti (rychlost, nekompatibilita), standardní postup je přes funkce - v grafickém režimu větší možnosti, pixel (picture element), počet je závislý na rozlišovací schopnosti adaptéru, monitoru - uložení informace o jednotlivých pixelech se liší podle použitého adaptéru - přímý přístup do videopaměti vyžaduje programování v assembleru, standardní postup je přes grafické funkce - textový režim je rychlejší, ovládání snadnější, omezený počet znaků
0. řádek 0. 1. 79. 1. řádek 159. offset = (((řádek x šířka_řádku) + sloupec) x 2) 160 = 10100000B = A0H 320 = 101000000B = 140H 24. řádek adresace řádků displeje: 0000H řádek 0 00A0H řádek 2 0140H řádek 4 01E0H řádek 6
Barevné režimy Paleta 16 barev 256 barev High color True color R G B
Adaptér Textový režim Grafický režim MDA 80 x 25 - monochromatický Hercules 80 x 25 720 x 348 monochromatický monochromatický CGA 80 x 25 (16 barev) 640 x 200 (monochromatický) 320 x 200 (4 barvy) EGA 80 x 25 (16 barev) 640 x 350 (16 barev) 80 x 43 (16 barev) VGA 80 x 25 (16 barev) 640 x 480 (16 barev) 80 x 50 (16 barev) 320 x 200 (256 barev) SVGA jako VGA 800 x 600 (16 barev) 1024 x 768 (16 barev) Historie grafických adaptérů