10. přednáška 10. 4. 2008 -soubory (soubory na elementární úrovni) -projekty

Preview:

DESCRIPTION

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/. - PowerPoint PPT Presentation

Citation preview

10. přednáška10. 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);

- 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ápisS_IREAD povoleno čteníS_IREAD | S_IWRITE povoleno čtení a zápis

Vytvoření souboru

Soubory na elementární úrovni

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 nenalezenoEMFILE 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říznak VýznamO_RDONLY Pro čtení lze použít pouze O_WRONLY Pro zápis jeden příznakO_RDWR Zápis, čtení

Příznak VýznamO_NDELAY pro komp. s UNIXO_APPEND Před každým zápisem se ukazatel souboru

nastaví na konecO_CREAT Pokud soubor existuje, nemá příznak

smyslO_TRUNC Existující soubor se zkrátí na nuluO_EXCL pro komp. s UNIXO_BINARY Binární režimO_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, ukazatelsouboru 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

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 blk je zapsána funkcíwrite() do souboru se symbolickým číslem cis_soub. Početslabik, 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 souborusdruž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 seodstraňuje znak CR, při znaku CTRL-Z čtení končí. ZnakyCTRL-Z a CR se nepočítají.

Čtení a zápis do elementárního souboru

Maximální počet slabik, které lze přečíst je 65534, neboť 65535je 0xFFFF (hodnota -1 - chyba). Při zjištění konce souboru jená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 typproudu 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:027Etmp2.txt 6 69F9:0292tmp3.txt 7 69F9:02A6

- č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

Projekty

- ř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 { …. } ….

- 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

Datové typy

Konstanty a makra

#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

}

- 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);

Funkce

#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){ …. }

- globální charakter některých dat

c1.c

c2.c

c3.c

Proměnné

- 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.

float GLOB = 9.9; #include "dat.h"…GLOB *= 6.2;…extern float GLOB;

#include "dat.h"…if(GLOB > 1234.5){ … }…

dat.c

dat.h b1.cb2.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 DATA#include "hl.h"#undef DATAint promenna_1 = 6;struct uiop str = {"AHOJ", ANO, 3.5};

#include "hl.h"void fce1(void){ … }void fce2(struct uiop *par){ … }

#define ANO 1#define NE 0struct 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 main(void){ fce2(&str); fce1();}

x3.c

hl.h

x1.c

x2.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)

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 long integer, nikoliv jako fyzická adresa, ostatní relační operátory používají pouze offset. Při zvyšování far ukazatele o 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 : 00030040 : 0056 -> 0045 : 0006500D : 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.

Správa paměti (platí pouze pro šestnáctibitové prostředí)

CS, DS, SS

SP

kód

zásobník

data

volná paměť

heap

do 64 KB

TINY

CS

SP

kód

zásobník

data

volná paměť

far heap

MEDIUM

volná paměť

DS, SS

pro každý zdrojovýsoubor až 64 KB

do 64 KB

sfile sfile A

sfile B

sfile Z

heap

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. řádek1. řádek

24. řádek

79.1.0.

159.

adresace řádků displeje: 0000H řádek 000A0H řádek 20140H řádek 401E0H řádek 6

offset = (((řádek x šířka_řádku) + sloupec) x 2)

160 = 10100000B = A0H320 = 101000000B = 140H

Barevné režimy

16 barev

256 barev

High color

True color

Paleta

R G B

Historie grafických adaptérů

Adaptér Textový režim Grafický režim

MDA 80 x 25 -monochromatický

Hercules 80 x 25 720 x 348monochromatický 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)

Recommended