Professional Documents
Culture Documents
PRZYKADOWY ROZDZIA
SPIS TRECI
KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG
TWJ KOSZYK
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK
CZYTELNIA
FRAGMENTY KSIEK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Profesjonalne programowanie.
Cz 1. Zrozumie komputer
Autor: Randall Hyde
Tumaczenie: Tomasz mijewski
ISBN: 83-7361-859-7
Tytu oryginau: Write Great Code.
Volume 1: Understanding the Machine
Format: B5, stron: 392
Chcesz zosta programist doskonaym?
Zacznij od poznania szczegw dziaania komputera
Zapis wartoci liczbowych oraz arytmetyka zmiennoprzecinkowa i binarna
Organizacja dostpu do pamici komputera
Proces wykonywania programu oraz operacje wejcia i wyjcia
Kod napisany przez profesjonalnego programist jest wydajny i efektywny.
Aby tworzy wydajny kod, naley pozna architektur komputera i sposb, w jaki
program jest wykonywany. Zrozumienie tego, w jaki sposb komputer realizuje kolejne
instrukcje programu i jak sowa kluczowe jzykw wysokiego poziomu s przenoszone
na rozkazy procesora, jest kluczem do napisania kodu, ktry po skompilowaniu
da szybko i bezbdnie dziaajcy program.
Profesjonalne programowanie. Cz 1. Zrozumie komputer to pierwszy tom serii
ksiek przeznaczonych dla tych programistw, ktrzy chc podnie swoje
kwalifikacje. Przedstawia wewntrzn architektur komputera od strony, ktrej
znajomo jest niezbdna programicie. Opisuje sposoby zapisu wartoci liczbowych
i tekstw, dziaania na liczbach binarnych i zmiennoprzecinkowych oraz logik Boolea.
Czytajc t ksik, dowiesz si, w jaki sposb procesor przetwarza rozkazy asemblera,
jak odbywa si dostp do danych zapisanych w pamici oraz jak przesyane s dane
do i z urzdze zewntrznych.
Zapis liczb w systemie binarnym, semkowym i szesnastkowym
Dziaania na liczbach binarnych i zmiennoprzecinkowych
Sposoby reprezentacji danych znakowych
Organizacja pamici i tryby adresowania
Zoone typy danych
Projektowanie ukadw cyfrowych i logika Boolea
Architektura procesora i rozkazy asemblera
Operacje wejcia i wyjcia
Jeli chcesz, aby napisane przez Ciebie oprogramowanie budzio podziw, koniecznie
przeczytaj t ksik.
Spis treci
Podzikowania .................................................................................. 9
Rozdzia 1. Co trzeba wiedzie o programowaniu doskonaym ............................ 11
1.1. Seria ksiek Profesjonalne programowanie .................................................... 11
1.2. O czym jest ta ksika ......................................................................................... 12
1.3. Wymagania wobec Czytelnika ............................................................................ 15
1.4. Cechy kodu doskonaego ..................................................................................... 15
1.5. Wymagane rodowisko ........................................................................................ 16
1.6. Dalsze informacje ................................................................................................ 17
Spis treci
5
6.2.4. Magistrale 64-bitowe ............................................................................. 136
6.2.5. Dostp do pamici w procesorach innych ni 80x86 ............................. 136
6.3. Kolejno bajtw ............................................................................................... 136
6.4. Zegar systemowy ............................................................................................... 141
6.4.1. Dostp do pamici a zegar systemowy ................................................... 142
6.4.2. Stany oczekiwania ................................................................................. 143
6.4.3. Pami podrczna .................................................................................. 145
6.5. Dostp procesora do pamici ............................................................................. 148
6.5.1. Bezporedni tryb adresowania pamici .................................................. 149
6.5.2. Tryb adresowania poredniego ............................................................... 149
6.5.3. Tryb adresowania indeksowanego ......................................................... 150
6.5.4. Skalowane indeksowane tryby adresowania .......................................... 151
6.6. Dodatkowe informacje ....................................................................................... 151
Spis treci
7
11.4.5. Polityka wymiany zawartoci wierszy ................................................... 282
11.4.6. Zapis danych w pamici ......................................................................... 283
11.4.7. Uycie pamici podrcznej i oprogramowanie ...................................... 284
11.5. Pami wirtualna, ochrona i stronicowanie ....................................................... 285
11.6. Zamiecanie ....................................................................................................... 288
11.7. NUMA i urzdzenia peryferyjne ....................................................................... 289
11.8. Oprogramowanie wiadome istnienia hierarchii pamici .................................. 290
11.9. Organizacja pamici w trakcie dziaania programu ........................................... 291
11.9.1. Obiekty statyczne i dynamiczne, wizanie, czas ycia .......................... 293
11.9.2. Kod, segmenty tylko do odczytu i segment staych ............................... 294
11.9.3. Segment zmiennych statycznych ........................................................... 294
11.9.4. Segment danych niezainicjalizowanych (BSS) ...................................... 295
11.9.5. Segment stosu ........................................................................................ 295
11.9.6. Segment sterty i dynamiczna alokacja pamici ...................................... 296
11.10. Dodatkowe informacje ...................................................................................... 301
Rozdzia 5.
Dane znakowe
Wprawdzie komputery s kojarzone gwnie z moliwociami obliczeniowymi, ale
tak naprawd znacznie czciej uywa si ich do przetwarzania danych znakowych.
Jeli wemiemy pod uwag, jak istotne we wspczesnych komputerach jest przetwarzanie znakw, pojmiemy, e bycie programist doskonaym wymaga gruntownego
zrozumienia danych i acuchw znakowych.
Pojcie znaku odnosi si do symbolu zrozumiaego dla czowieka lub dla maszyny,
zwykle niebdcego liczb. W zasadzie znak to symbol, ktry mona wpisa z klawiatury i zobaczy na monitorze. Pamitajmy, e poza literami do danych znakowych
zaliczaj si te znaki przestankowe, cyfry, spacje, tabulatory, znaki powrotu karetki
(klawisz ENTER), inne znaki kontrolne i znaki specjalne.
W tym rozdziale przyjrzymy si, jak w komputerze s zapisywane znaki, acuchy
i zbiory znakw. Omwimy te rne operacje na tych typach danych.
102
Nazwa tego znaku pochodzi z czasw, kiedy chodzio o przesunicie karetki maszyny do pisania.
Powrt karetki polega na fizycznym przesuniciu tej karetki tak, aby nastpny znak pojawi si przy
lewym brzegu papieru.
103
Oba znaki rni si tylko pitym bitem. Wielkie litery maj pity bit rwny zero, mae
rwny jeden. Mona skorzysta z tego, aby szybko zamienia mae litery na wielkie
i odwrotnie; wystarczy przeczy tylko jeden bit.
Bity pity i szsty decyduj o przynalenoci znaku do grupy (tabela 5.1). Wobec tego
mae litery na wielkie (lub na znaki specjalne) mona zamienia, ustawiajc bity pity
i szsty na zero.
Tabela 5.1. Grupy znakw ASCII wyznaczone przez pity i szsty bit
Bit 6.
Bit 5.
Grupa znakw
znaki kontrolne
Przyjrzyjmy si przez chwil kodom ASCII cyfr, pokazanym w tabeli 5.2. Dziesitny
zapis tych kodw niewiele nam mwi. Jednak zapis szesnastkowy ujawnia co wanego modszy pbajt kodu ASCII to binarny odpowiednik zapisywanej liczby. Jeli
odrzucimy starszy pbajt kodu (ustawimy go na zero), otrzymamy binarny zapis
odpowiedniej cyfry. Z drugiej strony, atwo moemy zamieni liczb binarn z zakresu 0..9 na jej odpowiednik ASCII; wystarczy ustawi starszy pbajt na %0011, czyli
dziesitne 3. Zauwamy, e moemy uy logicznej operacji AND, aby wymusi
wyzerowanie starszych bitw; tak samo za pomoc logicznego OR moemy wymusi
ustawienie starszych bitw na %0011 (dziesitnie 3). Wicej informacji o konwersji
acuchw na liczby Czytelnik znajdzie w rozdziale 2.
Mimo e ASCII jest standardem, kodowanie danych za jego pomoc nie gwarantuje
nam penej przenonoci midzy rnymi systemami. Chocia literze A na jednej maszynie bdzie odpowiadao A na innej, zakres standaryzacji znakw kontrolnych jest
niewielki. Faktycznie spord pierwszych 32 kodw kontrolnych ASCII uzupenionych
kodem delete z grupy ostatniej tylko cztery s powszechnie obsugiwane przez wikszo urzdze i programw. S to: backspace (BS), tabulator, powrt karetki (CR)
104
Dziesitnie
Szesnastkowo
48
$30
49
$31
50
$32
51
$33
52
$34
53
$35
54
$36
55
$37
56
$38
57
$39
i nowy wiersz (LF). Co gorsza, na rnych maszynach czsto te same kody kontrolne
s rnie obsugiwane. Szczeglnie nieprzyjemnym przypadkiem jest koniec wiersza.
W systemach Windows, MS-DOS, CP/M i innych koniec wiersza oznacza si par
znakw CR-LF. Apple Macintosh i wiele innych systemw oznacza koniec wiersza
pojedynczym znakiem CR. Z kolei Linux, BeOS i inne systemy z rodziny Unix oznaczaj go pojedynczym znakiem LF.
Prba przekazania zwykego pliku tekstowego midzy tymi systemami moe by rdem powanej frustracji. Nawet jeli uywamy standardowych znakw ASCII, i tak
musimy zawczasu skonwertowa dane. Na szczcie konwersje te s proste na tyle,
e wiele edytorw tekstu automatycznie obsuguje pliki z rnie koczcymi si wierszami. Istnieje te wiele darmowych programw wykonujcych stosowne konwersje.
Nawet jeli musimy sami oprogramowa tak konwersj, jest ona prosta kopiujemy
wszystkie znaki poza kocem wiersza, ktry odpowiednio zmieniamy.
105
106
Dawniej, kiedy terminale i komputery wykorzystyway odwzorowanie w pamici, dwubajtowe zestawy znakw byy mao przydatne. W przypadku generatorw znakw
wbudowanych w urzdzenie kady znak musia mie tak sam dugo, ograniczano
te liczb obsugiwanych znakw. Jednak kiedy zaczy dominowa matrycowe wywietlacze z programowymi generatorami znakw (Windows, Macintosh, Unix/XWindows),
uywanie dwubajtowych zestaww znakw stao si wygodne.
Wprawdzie zestawy dwubajtowe pozwalaj zapisywa w zwartej formie wiele rnych
znakw, ale przetwarzanie tekstu w takim formacie wymaga sporo mocy obliczeniowej.
Jeli na przykad mamy zakoczone zerami acuchy znakw dwubajtowych (konstrukcja typowa w C i C++), okrelenie liczby znakw w acuchu moe by nie lada
wyzwaniem. Chodzi o to, e niektre znaki potrzebuj dwch bajtw, a niektre tylko
jednego. Funkcja okrelajca dugo acucha musi przeglda znak po znaku, aby
znale znaki rozszerzajce i odkry w ten sposb miejsca, w ktrych s znaki dwubajtowe. To podwjne porwnanie podwaja czas okrelania dugoci acucha. Co gorsza,
wiele algorytmw powszechnie stosowanych do obsugi danych acuchowych zawodzi
w przypadku dwubajtowych zestaww znakw. Na przykad typowy sposb przemieszczania si w jzyku C po acuchu to zwikszanie lub zmniejszanie o jeden
wskanika, na przykad ++ptrChar lub --ptrChar. Wszystkie te mechanizmy nie zadziaaj w przypadku kodowania dwubajtowego. Osoby korzystajce z takich kodowa
zwykle posiadaj gotowe ju funkcje biblioteczne, ale wiele innych funkcji napisanych
przez nie lub przez kogo innego nie zadziaa. Z tego i innych powodw, jeli potrzebne
jest nam kodowanie wikszej ni 124 liczby znakw, powinnimy nastawi si na
korzystanie ze standardu Unicode, ktry zaraz zostanie opisany.
ASCII to kod 7-bitowy. Jeli najstarszych 9 bitw 16-bitowej wartoci Unicode jest zerami,
pozostaych 7 bitw to kod ASCII danego znaku.
107
w Unicode). Zestaw znakw Unicode zawiera nawet kody, ktre mog by uywane
jako znaki definiowane na potrzeby poszczeglnych aplikacji. W chwili pisania tej
ksiki zdefiniowano okoo poow z 65 536 dostpnych znakw; pozostae s zarezerwowane na rozszerzenia w przyszoci.
Obecnie wiele systemw operacyjnych i bibliotek do rnych jzykw programowania
zawiera doskona obsug Unicode. Na przykad system Microsoft Windows uywa
standardu Unicode wewntrznie5, co powoduje, e funkcje systemowe dziaaj szybciej,
jeli przekae im si acuchy Unicode, ni w przypadku przekazania acuchw ASCII
(kiedy przekazujemy do nowszych wersji Windows acuch ASCII, system najpierw
zamienia go z ASCII na Unicode i dopiero wtedy uywa API funkcji systemowej).
Analogicznie, kiedy Windows zwraca aplikacji acuch, jest to acuch Unicode; jeli
oczekuje ona acucha ASCII, Windows musi dodatkowo przeprowadzi stosown
konwersj.
Jednak Unicode ma te dwie powane wady. Po pierwsze, dane znakowe zajmuj dwa
razy wicej miejsca ni w przypadku ASCII lub innych kodowa jednobajtowych.
Chocia obecnie komputery maj znacznie wicej pamici ni kiedy (dotyczy to tak
pamici RAM, jak i pamici dyskowych), podwojenie rozmiaru plikw tekstowych,
baz danych i acuchw umieszczanych w pamici (jak acuchy przetwarzane przez
edytory i procesory tekstu) moe znaczco wpyn na wydajno systemu. Co gorsza,
skoro acuchy s obecnie dwukrotnie dusze, przetwarzanie acucha Unicode wymaga
prawie dwukrotnie wicej instrukcji ni przetwarzanie acucha, w ktrym znaki s
zapisywane na pojedynczych bajtach. Wobec tego funkcje obsugi acuchw mog
dziaa dwukrotnie wolniej ni funkcje przetwarzajce dane jednobajtowe6. Druga wada
Unicode jest taka, e wikszo istniejcych gdziekolwiek na wiecie plikw z danymi
jest zapisana jako ASCII lub EBCDIC, wic w przypadku korzystania w aplikacji
z Unicode pewn ilo czasu trzeba powici na konwersj midzy Unicode a innymi
zestawami znakw.
Cho Unicode jest standardem powszechnie akceptowanym, nadal nie wydaje si, eby
by w powszechnym uyciu (cho stale zyskuje na popularnoci). Mona si spodziewa,
e ju wkrtce przekroczy on mas krytyczn i stanie si wszechobecny. Jednak
jest to nadal kwestia przyszoci, wic w wikszoci przykadw w naszej ksice nadal
ogranicza si bdziemy do znakw ASCII. Ale ju niedugo zapewne w ksice takiej
jak ta trzeba bdzie si skupi raczej na Unicode.
Windows CE uywa wycznie Unicode. Do funkcji tego systemu w ogle nie ma moliwoci
przekazania acuchw ASCII.
108
109
Jednak acuchy zakoczone zerem maj te wady, wobec czego nie zawsze s optymaln struktur dla danych acuchowych. Wady ich uywania s nastpujce:
Funkcje do obsugi acuchw czsto dziaaj bardzo niewydajnie w ich
110
acuchy 7-bitowe.
Ograniczeni jestemy do 128 kodw znakw, cho w przypadku korzystania
Zwrmy uwag na to, e HLA jest asemblerem, wic mona i to bez trudu obsuy w nim
praktycznie dowolny rozsdny format acuchw. Natywny format acuchw HLA wykorzystywany
jest w staych literaach; jest on te uywany przez wikszo procedur z biblioteki standardowej HLA.
Tak naprawd, w zwizku z wymaganiami co do wyrwnania danych w pamici, narzut dla niektrych
acuchw moe siga 12 bajtw.
111
Format HLA wykorzystuje 4-bajtowy przedrostek opisujcy dugo; dziki temu dugo
ta moe by nieco wiksza ni cztery miliardy znakw (jest to oczywicie o wiele
wicej, ni w ogle znajduje praktyczne zastosowanie). HLA wstawia te na koniec
danych acuchowych bajt zerowy, dziki czemu acuchy HLA s zgodne funkcjami
obsugujcymi acuchy zakoczone zerem (pod warunkiem, e funkcje te nie zmieniaj
dugoci acuchw). Nastpne cztery dodatkowe bajty w acuchu HLA zawieraj
maksymaln dopuszczaln dugo acucha. Dziki temu dodatkowemu polu funkcje
obsugujce w HLA acuchy mog w razie potrzeby sprawdzi, czy nie wystpio
przepenienie. Na rysunku 5.2 pokazano posta acucha HLA w pamici.
Rysunek 5.2.
Format acuchw
HLA
Mi cech zmiennych acuchowych HLA jest to, e (jako obiekty tylko do odczytu)
s one kompatybilne z acuchami zakoczonymi zerem. Na przykad, jeli mamy
funkcj jzyka C (lub innego) spodziewajc si jako parametru acucha zakoczonego zerem, moemy wywoa j, przekazujc jej acuch HLA:
jakasFunkcjaC( zmiennaLancuchowaHLA );
Jedynym problemem jest to, e funkcja ta nie moe w aden sposb zmienia dugoci acucha (gdy kod C nie skorygowaby pola okrelajcego dugo). Oczywicie,
przy powrocie zawsze mona byoby uy funkcji C strlen, aby sprawdzi dugo
acucha i w razie potrzeby j skorygowa, ale modyfikowanie dugoci acuchw
HLA z zewntrz w zasadzie jest kiepskim pomysem.
112
113
pascalString :string(255);
Kiedy taki program dziaa, nie mona w aden sposb zwikszy maksymalnej wielkoci acuchw statycznych. Nie mona te zmniejszy iloci rezerwowanej na nie
pamici. acuchy te zawsze zajm 256 bajtw i kropka. Zalet acuchw statycznych
jest to, e kompilator moe okreli maksymaln ich dugo na etapie kompilacji
i niejawnie przekaza t informacj do funkcji obsugujcych, dziki czemu moliwe
jest w trakcie dziaania programu kontrolowanie narusze dugoci.
Ale przecie HLA jest asemblerem, wic mona stworzy w nim take acuchy czysto statyczne
i w peni dynamiczne.
10
Tak naprawd mona wywoa strrealloc do zmiany wielkoci acucha HLA, ale acuchy
dynamiczne zaatwiaj to automatycznie, czego nie umoliwiaj funkcje obsugi acuchw
w przypadku wykrycia przepenienia.
114
115
mnie pokazay, e acuchy te s bardzo podobne do znanych z HLA. Delphi wykorzystuje zakoczone zerem cigi znakw poprzedzone dugoci acucha i licznikiem
odwoa (zamiast dugoci maksymalnej uywanej w HLA). Na rysunku 5.4 pokazano
ukad takiego acucha w pamici.
Rysunek 5.4.
Format danych znakowych
w Delphi i Kyliksie
Tak jak w HLA, tak i w Delphi zmienne acuchowe to wskaniki do pierwszego znaku
faktycznych danych. Aby okreli dugo i liczb odwoa, procedury Delphi i Kyliksa
wykorzystuj ujemne offsety 4 i 8. Jednak, jako e format ten nie zosta opublikowany, w aplikacjach nigdy nie naley siga do tych pl bezporednio. Delphi i Kylix
zawieraj funkcj okrelajc dugo acucha, wic tak naprawd nie ma powodu
siga bezporednio do samego pola.
116
Opis
Przynaleno
Pozwala sprawdzi, czy dany znak naley do zbioru (zwraca prawd lub fasz).
Przecicie
Suma
Rnica
Pobranie
Podzbir
Podzbir waciwy
Zwraca prawd, jeli jeden zbir znakw jest podzbiorem waciwym drugiego.
Nadzbir
Nadzbir waciwy
Zwraca prawd, jeli jeden zbir znakw jest nadzbiorem waciwym drugiego.
Rwno
Nierwno
Zwraca prawd, jeli jeden zbir znakw nie jest rwny drugiemu.
pamici, zwykle kademu znakowi ze zbioru przypisany jest pojedynczy bajt. Wobec
tego taki zbir znakw wymaga 16 bajtw (128 bitw) pamici w przypadku 128 znakw
lub 32 bajtw (256 bitw) w przypadku 256 moliwych znakw. Taki zapis zestawu
znakw nazywamy zbiorem przynalenoci.
Jzyk HLA wykorzystuje 16-bajtow tablic do zapisu 128 moliwych znakw ASCII.
Ta 128-bitowa tablica jest uoona w pamici tak, jak to pokazano na rysunku 5.5.
Rysunek 5.5.
Zapis zbioru znakw
w jzyku HLA
Zerowy bit zerowego bajta odpowiada znakowi ASCII o kodzie zero (znakowi NUL).
Jeli bit ten jest ustawiony, dany zestaw znakw zawiera znak NUL. Jeli bit ten jest
wyzerowany, zbir nie zawiera znaku NUL. Analogicznie, bit pierwszy smego bajta
odpowiada znakowi ASCII o kodzie 65, czyli wielkiej literze A. Bit 65. bdzie zawiera jedynk, jeli w opisywanym zbiorze znakw znak A si pojawia i zero w przeciwnym razie.
W Pascalu (w jzyku rodowisk Delphi i Kylix) wykorzystuje si analogiczny schemat
do zapisu zbiorw znakw. W Delphi zbir znakw moe zawiera ich do 256, wic
takie struktury zajmuj 256 bitw (czyli 32 bajty).
Zbiory znakw mona zapisywa te na rne inne sposoby, ale zalet opisanej tu postaci
wektora bitowego (czyli tablicy bitowej) jest atwo implementacji takich operacji
na zbiorach, jak suma, przecicie, rnica, porwnanie i sprawdzenie przynalenoci.
117
118
na zewntrzne (na przykad ASCII) na potrzeby funkcji wejcia i wyjcia. Jeli dobierzemy dobre kodowanie, ktre pozwoli poprawi wydajno naszego programu, utrata
wydajnoci zwizana z przekodowaniem wejcia-wyjcia bdzie opacalna. Jak zatem
dobra kodowanie do wasnego zestawu znakw?
Pierwsze, nad czym mona by si zastanowi, to ile znakw zamierzamy obsugiwa.
Oczywicie, liczba znakw bezporednio wpynie na wielko danych znakowych.
Typowym wyborem jest 256 znakw, gdy to bajty s najpowszechniej stosowanym
elementarnym typem danych. Jednak trzeba pamita, e jeli nie potrzebujemy 256
znakw, nie powinnimy tworzy tak duego zestawu. Jeli na przykad wystarczy nam
128 znakw, albo nawet tylko 64, to nasze pliki tekstowe bd mniejsze. Analogicznie, przekazywanie danych przy uyciu specjalizowanych zestaww znakw bdzie
szybsze, jeli bdziemy musieli przekaza zawsze sze albo siedem bitw zamiast
omiu. Jeli z kolei bdziemy potrzebowali wicej ni 256 znakw, trzeba rozway
zalety i wady stosowania wielu stron kodowych, korzystania ze znakw dwubajtowych,
czyli 16-bitowych. Poza tym pamita trzeba, e zestaw Unicode umoliwia definiowanie
wasnych znakw. Jeli zatem potrzebujemy wicej ni 256 znakw, warto pomyle
nad uyciem Unicode i zawartych w nim znakw uytkownika, co pozwoli nam przynajmniej w jakim stopniu pozosta w zgodzie ze standardami.
W tej czci rozdziau zdefiniujemy 128-elementowy zestaw znakw wykorzystujcy
pene, 8-bitowe bajty. Podstawowym naszym zadaniem bdzie zmiana ukadu kodw
ASCII tak, aby wygodniej byo na nich robi pewne obliczenia; poza tym zmienimy
znaczenie czci kodw kontrolnych tak, aby byy przydatne we wspczesnych komputerach, a nie w archaicznych dalekopisach. Dodamy te kilka nowych znakw,
niewystpujcych w standardzie ASCII. Gwnym celem tego wiczenia bdzie uzyskanie wikszej wydajnoci obliczeniowej, a nie samo tworzenie nowych znakw. Nasz
zestaw znakw nazwiemy zestawem HyCode.
Tworzc w tym rozdziale zestaw HyCode, nie staramy si stworzy nowego standardu kodowania. HyCode to po prostu prezentacja tego, jak mona stworzy wasny,
dostosowany do specyficznych potrzeb zestaw znakw i w ten sposb udoskonali
swoje programy.
119
bdzie trzeba samemu napisa od nowa. Zestaw znakw HyCode nie rezerwuje jako
koca acucha znaku zerowego i to dobrze, gdy, jak widzielimy, takie acuchy
nie dziaaj zbyt wydajnie.
Jeli przyjrzymy si programom korzystajcych z funkcji do obsugi acuchw, stwierdzimy, e pewne funkcje wystpuj szczeglnie czsto:
Sprawdzanie, czy znak jest cyfr.
Konwersja znaku cyfry na odpowiadajc mu liczb.
Konwersja liczby na odpowiadajcy jej znak cyfry.
Sprawdzanie, czy znak jest liter.
Sprawdzanie, czy znak jest ma liter.
Sprawdzanie, czy znak jest wielk liter.
Porwnywanie dwch znakw (lub acuchw) bez uwzgldniania wielkoci liter.
Sortowanie zbioru acuchw (z uwzgldnieniem i bez uwzgldnienia
wielkoci liter).
Sprawdzanie, czy dany znak jest znakiem alfanumerycznym.
Sprawdzanie, czy dany znak moe wystpowa w identyfikatorach.
Sprawdzanie, czy dany znak jest operatorem arytmetycznym lub logicznym.
Sprawdzanie, czy znak jest nawiasem (czyli jednym ze znakw (, ), [, ], {, },
Nasz zestaw HyCode zdefiniujemy tak, aby opisane dziaania byy tak szybkie i tak
proste, jak tylko jest to moliwe. Znaczn przewag nad kodem ASCII moemy uzyska, jeli wszystkie znaki wchodzce w skad jakiej grupy zestawimy razem na
przykad wszystkie litery lub wszystkie znaki sterujce. Dziki temu bdziemy mogli
robi dowolne z powyszych sprawdze za pomoc tylko dwch porwna. Na przykad wygodnie byoby sprawdza, czy dany znak jest znakiem przestankowym, porwnujc go z wartociami ograniczajcymi znaki przestankowe z gry i z dou. Nie
mona w ten sposb obsuy wszystkich moliwych zakresw porwna, ale warto
uwzgldni zakresy wystpujce najczciej. Wprawdzie w ASCII pewne cigi znakw
s uoone bardzo sensownie, ale mona je jeszcze poprawi. Na przykad nie mona
tam sprawdzi, czy znak jest przestankowy, przy ograniczeniu si do dwch porwna,
gdy znaki te s porozrzucane po caym zestawie.
120
121
bit znaku wskazuje, czy znak jest ma liter (najmodszy bit jest zerem), czy wielk
(najmodszy bit jest jedynk). HyCode wykorzystuje nastpujce kodowanie liter:
a:76, A:77, b:78, B:79, c:80, C:81, ..., y:124, Y:125, z:126, Z:127
Sprawdzanie, czy dany znak HyCode jest wielk, czy ma liter, jest nieco trudniejsze
od sprawdzania, czy jest liter, ale w asemblerze jest to i tak prostsze od analogicznego
sprawdzenia kodu ASCII. Aby sprawdzi, czy znak jest danej wielkoci, robi si dwa
porwnania: najpierw sprawdza si, czy jest on liter, a potem okrela jego wielko.
W C i C++ uylibymy do tego nastpujcych instrukcji:
if( (c >= 76) && (c & 1))
{
// kod wykonywany w przypadku wielkich liter
}
if( (c >= 76 && !(c & 1))
{
// kod wykonywany w przypadku maych liter
}
Wyraenie (c & 1) zwraca prawd, jeli najmodszy bit c jest jedynk, czyli kiedy
mamy do czynienia z wielk liter. Analogicznie !(c & 1) zwraca prawd, jeli najmodszy bit c jest zerem, czyli kiedy c jest ma liter. W przypadku asemblera 80x86
mona sprawdzi, czy znak jest wielk, czy ma liter, za pomoc trzech instrukcji
maszynowych:
// Uwaga: ROR(1, AL) powoduje odwzorowanie maych liter na zakres $26..$3F (38..63),
//
a wielkich na zakres $A6..$BF (166..191). Wszystkie inne znaki s
//
odwzorowywane na mniejsze wartoci z tych zakresw.
ror( 1, al );
cmp( al, $26 );
jnae NotLower;
122
Tak wanie wyglda kolejno sownikowa, poza tym takiej kolejnoci uytkownicy
oczekuj intuicyjnie.
Porwnywanie niezalene od wielkoci liter jest tylko nieznacznie trudniejsze od porwnywania z uwzgldnieniem tej wielkoci (i o wiele atwiejsze od porwnywania
bez uwzgldniania wielkoci liter w ASCII). Kiedy porwnujemy dwie litery, po prostu
maskujemy ich najmodsze bity (lub ustawiamy je na jeden) i automatycznie uzyskujemy porwnanie niezalene od ich wielkoci.
Aby zobaczy, jakie korzyci daje HyCode przy porwnywaniu bez uwzgldnienia
wielkoci liter, przyjrzyjmy si takiemu porwnaniu w C i C++ dla znakw ASCII:
if( toupper( c ) == toupper( d ))
{
// kod obsugi c==d z dokadnoci co do wielkoci liter.
}
Kod ten wyglda cakiem przyzwoicie, ale przyjrzyjmy si teraz funkcji (a raczej makru)
toupper12.
#define toupper(ch) ((ch >= 'a' && ch <= 'z') ? ch & 05f : ch )
Teraz, kiedy mamy ju takie makro, preprocesor jzyka C pokazany powyej kod
rozwinie nastpujco:
if
(
((c >= 'a' && c <= 'z') ? c & 0x5f : c )
== ((d >= 'a' && d <= 'z') ? d & 0x5f : d )
)
{
// kod obsugi c==d z dokadnoci co do wielkoci liter.
}
12
Tak naprawd w standardowej bibliotece C moe by jeszcze gorzej: obecnie biblioteki te zawieraj
tablice przekodowa odwzorowujce zakresy znakw, ktre jednak tu pominiemy.
123
Kiedy uywamy HyCode, porwnanie bez uwzgldniania wielkoci liter jest znacznie
prostsze. Oto odpowiedni kod asemblera HLA.
// Sprawdzamy, czy CL jest liter. Nie trzeba porwnywa DL, gdy jeli
// DL nie jest liter, porwnanie zawsze zawiedzie.
cmp( cl, 76);
jb TestEqual;
or( 1, cl );
or( 1, dl );
TestEqual:
cmp( cl, dl );
jb TestEqual;
TheyreEqual:
// Kod obsugujcy c==d przy porwnaniu bez uwzgldnienia wielkoci liter.
NotEqual:
Jak wida, w cigu HyCode do porwnania dwch znakw uywa si poowy instrukcji.
124
Szczeglnie asembler HLA zawiera szeroki zestaw funkcji do obsugi znakw, acuchw, zestaww znakw i do dopasowywania wzorcw. Podrcznik biblioteki standardowej HLA dostpny jest pod adresem http://webster.cs.ucr.edu.
125
Szesnastkowo
Dziesitnie
Znak
Binarnie
Szesnastkowo
Dziesitnie
Znak
0000_0000
00
0001_1110
1E
30
End
0000_0001
01
0001_1111
1F
31
Home
0000_0010
02
0010_0000
20
32
PageDown
0000_0011
03
0010_0001
21
33
PageUp
0000_0100
04
0010_0010
22
34
w lewo
0000_0101
05
0010_0011
23
35
w prawo
0000_0110
06
0010_0100
24
36
w gr
0000_0111
07
0010_0101
25
37
w d (nowy
wiersz)
0000_1000
08
0010_0110
26
38
spacja
nierozdzielajca
0000_1001
09
0010_0111
27
39
akapit
0000_1010
0A
10
klawiatura
numeryczna
0010_1000
28
40
powrt
karetki
0000_1011
0B
11
kursor
0010_1001
29
41
nowy wiersz
(Enter)
0000_1100
0C
12
funkcja
0010_1010
2A
42
tabulator
0000_1101
0D
13
alt
0010_1011
2B
43
spacja
0000_1110
0E
14
control
0010_1100
2C
44
0000_1111
0F
15
polecenie
0010_1101
2D
45
0001_0000
10
16
len
0010_1110
2E
46
0001_0001
11
17
len128
0010_1111
2F
47
0001_0010
12
18
bin128
0011_0000
30
48
0001_0011
13
19
EOS
0011_0001
31
49
0001_0100
14
20
EOF
0011_0010
32
50
<
0001_0101
15
21
kontrola
0011_0011
33
51
>
0001_0110
16
22
break
(przerwanie)
0011_0100
34
52
0001_0111
17
23
escape
(cancel)
0011_0101
35
53
0001_1000
18
24
pauza
0011_0110
36
54
0001_1001
19
25
dzwonek
0011_0111
37
55
&
0001_1010
1A
26
tabulacja
wstecz
0011_1000
38
56
0001_1011
1B
27
backspace
0011_1001
39
57
0001_1100
1C
28
delete
0001_1101
1D
29
insert
0011_1010
3A
58
0101_1101
5D
93
0011_1011
3B
59
0101_1110
5E
94
126
Szesnastkowo
Dziesitnie
Znak
Binarnie
Szesnastkowo
Dziesitnie
Znak
0011_1100
3C
60
0101_1111
5F
95
0011_1101
3D
61
0110_0000
60
96
0011_1110
3E
62
0110_0001
61
97
0011_1111
3F
63
0110_0010
62
98
0100_0000
40
64
'
0110_0011
63
99
0100_0001
41
65
0110_0100
64
100
0100_0010
42
66
0110_0101
65
101
0100_0011
43
67
0110_0110
66
102
0100_0100
44
68
"
0110_0111
67
103
0100_0101
45
69
'
0110_1000
68
104
0100_0110
46
70
0110_1001
69
105
0100_0111
47
71
0110_1010
6A
106
0100_1000
48
72
0110_1011
6B
107
0100_1001
49
73
0110_1100
6C
108
0100_1010
4A
74
0110_1101
6D
109
0100_1011
4B
75
0110_1110
6E
110
0100_1100
4C
76
0110_1111
6F
111
0100_1101
4D
77
0111_0000
70
112
0100_1110
4E
78
0111_0001
71
113
0100_1111
4F
79
0111_0010
72
114
0101_0000
50
80
0111_0011
73
115
0101_0001
51
81
0111_0100
74
116
0101_0010
52
82
0111_0101
75
117
0101_0011
53
83
0111_0110
76
118
0101_0100
54
84
0111_0111
77
119
0101_1010
55
85
0111_1000
78
120
0101_0110
56
86
0111_1001
79
121
0101_0111
57
87
0111_1010
7A
122
0101_1000
58
88
0111_1011
7B
123
0101_1001
59
89
0111_1100
7C
124
0101_1010
5A
90
0111_1101
7D
125
0101_1011
5B
91
0111_1110
7E
126
0101_1100
5C
92
0111_1111
7F
127