cpp2 LEKCJA37


LEKCJA 37: KAŹDY DYSK JEST ZA MAŁY, A KAŹDY PROCESOR ZBYT
WOLNY...
________________________________________________________________
W trakcie tej lekcji dowiesz się, jak komputer dysponuje swoimi
zasobami w środowisku tekstowym (DOS).
________________________________________________________________

Truizmy użyte w tytule mają znaczyć, że "zasoby najlepszego
nawet komputera są ograniczone" i zwykle okazują się
wystarczające tylko do pewnego momentu. Najbardziej newralgiczne

zasoby to:

* czas mikroprocesora i
* miejsce w pamięci operacyjnej.

Tworzone przez nas programy powinny wystrzegać się zatem
najcięższych grzechów:

* nie pozwalać mikroprocesorowi na słodkie nieróbstwo;

Rzadko uzmysławiamy sobie, że oczekiwanie na naciśnięcie
klawisza przez użytkownika (czasem po przeczytaniu napisu na
ekranie) trwa sekundy (1, 2, .... czasem 20), a każda sekunda
lenistwa PC to stracone miliony cykli mikroprocesora.

* oszczędnie korzystać z pamięci dyskowej, a szczególnie
oszczędnie z pamięci operacyjnej RAM.

MODELE PAMIĘCI IBM PC.

Jak zapewne wiesz, Twój PC może mieć:

* pamięć ROM (tylko do odczytu),
* konwencjonalną pamięć RAM (640 KB),
* pamięć rozszerzoną EMS i XMS,
* pamięć karty sterownika graficznego ekranu (np. SVGA-RAM),
* pamięć Cache dla buforowania operacji dyskowych.

Najczęściej stosowane modele pamięci to:

* Small - mały,
* Medium - średni,
* Compact - niewielki (tu mam wątpliwość, może "taki sobie" ?),
* Large - duży,
* Huge - jeszcze większy, odległy.

Dodatkowo może wystąpić

* Tiny - najmniejszy.

Taki podział został spowodowany segmentacją pamięci komputera
przez procesory Intel 8086 i podziałem pamięci na bloki o
wielkości 64 KB. Model Small (Tiny, jeśli jest) jest najszybszy,

ale najmniej pojemny. Model Huge - odwrotnie - najpojemniejszy,
za to najwolniejszy. Model Tiny powoduje ustawienia wszystkich
rejestrów segmentowych mikroprocesora na tę samą wartość
(początek tej samej stronicy pamięci) i umieszczenie wszystkich
zasobów programu wewnątrz wspólnego obszaru pamięci o wielkości
nie przekraczającej 64 KB. Wszystkie skoki są wtedy "krótkie", a

wszystkie pointery (adresy) 16-bitowe. Kompilacja z
zastosowaniem modelu Tiny pozwala uzyskać program wykonywalny w
wersji *.COM (a nie *.EXE). Ale niestety nie wszystkie programy
mieszczą się w 64 KB. W modelu Small segment kodu jest jeden
(kod max. 64 K) i segment danych też tylko jeden (dane max. 64
K), ale są to już dwa różne segmenty. Zestawienia
najważniejszych parametrów poszczególnych modeli pamięci
przedstawia tabelka poniżej:

Modele pamięci komputera IBM PC.
________________________________________________________________

Model Segment kodu Segment danych *dp *cp
________________________________________________________________

Tiny 1 1 (CS = DS) 16 bit 16 bit
Small 1 1 16 bit 16 bit
Medium wiele 1 16 bit 32 bit
Compact 1 wiele 32 bit 16 bit
Large wiele wiele 32 bit 32 bit
Huge wiele wiele 32 bit 32 bit
________________________________________________________________

*dp - data pointer - wskaźnik do danych (near/far)
*cp - code pointer - wskaźnik do kodu.
Large - kod + dane = max. 1 MB.
Huge - kod = max. 1 MB, wiele segmentów danych po 64 K każdy.

Wynikające z takich modeli pamięci kwalifikatory near, far, huge

dotyczące pointerów w C++ nie są akceptowane przez standard ANSI

C (ponieważ odnoszą się tylko do IBM PC i nie mają charakteru
uniwersalnego). Trzeba tu zaznaczyć, że typ wskaźnika jest przez

kompilator przyjmowany domyślnie (automatycznie) zgodnie z
wybranym do kompilacji modelem pamięci. Jeśli poruszamy się
wewnątrz niewielkiego obszaru pamięci, możesz "forsować" bliższy

typ pointera, przyspieszając tym samym działanie programów:

huge *p;
...
near *ptr; //Bliski pointer
...
near int Funkcja(...) //Bliska funkcja
{
...
}
#define ILE (1024*640)

near unsigned int Funkcja(void)
{
huge char *ptr; // tu długi pointer jest niezbędny
long suma = 0;
for (p = 0; p < ILE; p++) suma += *p;
return (suma);
}

Zarówno zadeklarowanie funkcji jako bliskiej (near), jak i jako
statycznej (static) powoduje wygenerowanie uproszczonej
sekwencji wywołania funkcji przez kompilator. Daje to w efekcie
mniejszy i szybszy kod wynikowy.

IDENTYFIKACJA KLAWISZY.

Znane Ci z pliku i "klasyczne" funkcje
obsługi konsoli mają pewne zalety. Korzystanie z klasycznych,
nieobiektowych mechanizmów powoduje z reguły wygenerowanie
znacznie krótszego kodu wynikowego. Funkcje scanf() i gets()
wymagają wciśnięcia klawisza [Enter]. Dla szybkiego dialogu z
komputerem znacznie bardziej nadają się szybsze getch() i
kbhit(). Ponieważ klawiatura zawiera także klawisze specjalne
(F1 ... F10, [Shift], [Del], itp.), pełną informację o stanie
klawiatury można uzyskać za pośrednictwem funkcji bioskey(),
korzystającej z przerywania BIOS Nr 16. Oto krótki przykład
zastosowania funkcji bioskey():

#include "bios.h"
#include "ctype.h"
#include "stdio.h"
#include "conio.h"

# define CTRL 0x04
# define ALT 0x08
# define RIGHT 0x01
# define LEFT 0x02

int klawisz, modyfikatory;
void main()
{
clrscr();
printf("Funkcja zwraca : %d", bioskey(1));
printf("\n Nacisnij klawisz ! \n");
while (!bioskey(1));
printf("Funkcja zwrocila: %c", bioskey(1));
printf("\nKod: %d", (char)bioskey(1));
...

A to jeszcze inny sposób korzystania z tej bardzo przydatnej
funkcji, tym razem z innymi parametrami:

/* Funkcja z parametrem (0) zwraca kod klawisza: ------ */

klawisz = bioskey(0);

/* Funkcja sprawdza stan klawiszy specjalnych --------- */

modyfikatory = bioskey(2);
if (modyfikatory)
{
printf("\n");
if (modyfikatory & RIGHT) printf("RIGHT");
if (modyfikatory & LEFT) printf("LEFT");
if (modyfikatory & CTRL) printf("CTRL");
if (modyfikatory & ALT) printf("ALT");
printf("\n");
}
/* drukujemy pobrany klawisz */
if (isalnum(klawisz & 0xFF))
printf("'%c'\n", klawisz);
else
printf("%#02x\n", klawisz);
}

Należy tu zwrócić uwagę, że funkcje kbhit() i bioskey() nie
dokonują czyszczenia bufora klawiatury. Identyfikują znak
(znaki) w buforze, ale pozostawiają bufor w stanie niezmienionym

do dalszej obróbki. Zwróć uwagę, że funkcja getch() może
oczekiwać na klawisz w nieskończoność. Sprawdzić szybciej, czy
użytkownik nacisnął już cokolwiek możesz np. tak:

if (kbhit()) ...; if (!kbhit()) ...;

while (!bioskey(1)) ... if (bioskey(1)) ...;

Inną wielce przydatną "szybką" funkcją jest getch(). Oto
praktyczny przykład pobierania i testowania naciśniętych
klawiszy klawiatury.

[P131.CPP]

# include "stdio.h"
# include "conio.h"

char z1, z2;

void Odczyt(void)
{
z2 = '\0';
z1 = getch();
if (z1 == '\0') z2 = getch();
}

main()
{
clrscr();
printf("\nKropka [.] = Quit");
printf("\nRozpoznaje klawisze [F1] ... [F3] \n\n");

for (;;)
{
while(!kbhit());
Odczyt();
if (z1 == '.') break;
if (z1 != '\0') printf("\nZnak: %c", z1);
else
switch (z2)
{
case ';' : printf("\n F1"); break;
case '<' : printf("\n F2"); break;
case '=' : printf("\n F3"); break;
default : printf("\n Inny klawisz specjalny!");
}
}
return 0;
}

Klawisze specjalne powodują wygenerowanie dwubajtowego kodu
(widzianego w powyższym przykładowym programie jako dwa
jednobajtowe znaki z1 i z2). Funkcja getch() pobiera te bajty z
bufora klawiatury kolejno jednocześnie czyszcząc bufor. W
przypadku klawiszy specjalnych pierwszy bajt jest zerowy (NULL,
'\0', 00h), co jest sprawdzane w programie. A oto tabela kodów
poszczególnych klawiszy:

Kody klawiszy klawiatury IBM PC.
________________________________________________________________

Klawisze Kody ASCII (dec)
________________________________________________________________

Home G 71 (00:47h) '\0', 'G'
End O 79 (00:4Fh) '\0', 'O'
PgUp I 73
PgDn Q 81
Ins R 82
Del S 83
F1 ; 59
F2 ... F10 <, ... D 60, ... 68
Shift + F1 T 84
...
Shift + F10 ] 93
Ctrl + F1 ^ 94
...
Ctrl + F10 f 103
Alt + F1...F10 h, ... q 104, ... 113
Alt + 1...9 x, ... Ą (?) 120, ... 128
Alt + 0 Ć (?) 129

Strzałki kursora:
LeftArrow K 75
RightArrow M 77
UpArrow H 72
DownArrow P 80

Ctrl + PgDn v 118
Ctrl + PgUp Ń (?) 132
Ctrl + Home w 119
Ctrl + End u 117
________________________________________________________________


Wyprowadzanie znaków na ekran można przeprowadzić szybciej
posługując się przerywaniem DOS INT 29H. Drukowanie na ekranie w

trybie tekstowym przebiega wtedy szybciej niż robią to
standardowe funkcje , , czy .
Poniżej prosty przykład praktyczny wykorzystania przerywania
29H:

[P132.CPP]

# include
# include
# pragma inline

void SpeedBox(int, int, int, int, char);

main()
{
clrscr();
for (; !kbhit(); )
{
int x = rand() % 40;
int y = rand() % 12;
SpeedBox(x, y, (80 - x), (24 - y), ('' + x % 50));
}
return 0;
}

void SpeedBox(int x1, int y1, int x2, int y2, char znak)
{
int k;

for (; y1 < y2; y1++) { gotoxy(x1, y1);
for (k = x1; k < x2; k++)
{
asm MOV AL, znak
asm INT 29H
}
}
}

[Z]
________________________________________________________________
1. Opracuj program pozwalający porównać szybkość wyprowadzania
danych na ekran monitora różnymi technikami (cout, puts(),
printf(), asm).
2. Porównaj wielkość plików wynikowych .EXE powstających w
różnych wariantach z poprzedniego zadania.
________________________________________________________________



Wyszukiwarka

Podobne podstrony:
cpp2 LEKCJA43
cpp2 LEKCJA33
cpp2 LEKCJA15
cpp2 LEKCJA10
cpp2 LEKCJA38
cpp2 LEKCJA18
cpp2 LEKCJA19
cpp2 LEKCJA2
cpp2 LEKCJA14
cpp2 LEKCJA48
cpp2 LEKCJA44
cpp2 LEKCJA1
cpp2 LEKCJA22
cpp2 LEKCJA46
cpp2 LEKCJA35

więcej podobnych podstron