ďťż

Blog literacki, portal erotyczny - seks i humor nie z tej ziemi


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.
________________________________________________________________
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • qualintaka.pev.pl
  •