You are on page 1of 33

IDZ DO

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

Rozdzia 2. Zapis liczb ...................................................................................... 19


2.1. Czym jest liczba? ................................................................................................. 19
2.2. Systemy liczbowe ................................................................................................ 20
2.2.1. Dziesitny pozycyjny system liczbowy ................................................... 21
2.2.2. Podstawa .................................................................................................. 22
2.2.3. Binarny system liczbowy ......................................................................... 23
2.2.4. Szesnastkowy system liczbowy ............................................................... 24
2.2.5. Liczby semkowe .................................................................................... 26
2.3. Konwersja midzy liczb a tekstem ..................................................................... 28
2.4. Zapis liczb cakowitych ....................................................................................... 29
2.4.1. Bity .......................................................................................................... 29
2.4.2. acuchy bitowe ...................................................................................... 30
2.5. Liczby ze znakiem i bez znaku ............................................................................ 32
2.6. Pewne przydatne cechy liczb binarnych .............................................................. 34
2.7. Rozszerzenie znakiem, uzupenienie zerami i zawenie .................................... 35
2.8. Nasycenie ............................................................................................................ 38
2.9. Zapis dziesitny kodowany binarnie (BCD) ........................................................ 39
2.10. Zapis staopozycyjny ........................................................................................... 40
2.11. Skalowane formaty liczbowe ............................................................................... 43
2.12. Zapis wymierny ................................................................................................... 45
2.13. Wicej informacji ................................................................................................ 45

Rozdzia 3. Arytmetyka binarna i dziaania na bitach ......................................... 47


3.1. Dziaania arytmetyczne na liczbach dwjkowych i szesnastkowych ................... 47
3.1.1. Dodawanie wartoci binarnych ................................................................ 48
3.1.2. Odejmowanie liczb binarnych .................................................................. 49
3.1.3. Mnoenie wartoci binarnych .................................................................. 50
3.1.4. Dzielenie wartoci binarnych ................................................................... 51
3.2. Operacje logiczne na bitach ................................................................................. 52
3.3. Operacje logiczne na liczbach binarnych i cigach bitw .................................... 54

Profesjonalne programowanie. Cz 1. Zrozumie komputer


3.4. Przydatne operacje bitowe ................................................................................... 55
3.4.1. Sprawdzanie poszczeglnych bitw acucha za pomoc operatora AND ....55
3.4.2. Sprawdzanie, czy grupa bitw zawiera same zera ...........................................56
3.4.3. Porwnywanie zestawu bitw z acuchem binarnym ....................................56
3.4.4. Tworzenie licznikw modulo n za pomoc operacji AND ..............................57
3.5. Przesunicia i rotacje ........................................................................................... 58
3.6. Pola bitowe i pakowanie danych .......................................................................... 61
3.7. Pakowanie i rozpakowywanie danych ................................................................. 64
3.8. Wicej informacji ................................................................................................ 68

Rozdzia 4. Zapis zmiennopozycyjny .................................................................. 69


4.1. Wprowadzenie do arytmetyki zmiennopozycyjnej .............................................. 69
4.2. Formaty zmiennopozycyjne IEEE ....................................................................... 74
4.2.1. Zmiennopozycyjny format pojedynczej precyzji ..................................... 75
4.2.2. Format zmiennopozycyjny o podwjnej precyzji .................................... 77
4.2.3. Format zmiennopozycyjny zwikszonej precyzji ..................................... 77
4.3. Normalizacja i wartoci nienormalizowane ......................................................... 78
4.4. Zaokrglanie ........................................................................................................ 79
4.5. Specjalne wartoci zmiennopozycyjne ................................................................ 80
4.6. Wyjtki oblicze zmiennopozycyjnych ............................................................... 82
4.7. Dziaania zmiennopozycyjne ............................................................................... 82
4.7.1. Zapis liczb zmiennopozycyjnych ............................................................. 83
4.7.2. Dodawanie i odejmowanie zmiennopozycyjne ........................................ 83
4.7.3. Mnoenie i dzielenie zmiennopozycyjne ................................................. 93
4.8. Wicej informacji ................................................................................................ 99

Rozdzia 5. Dane znakowe .............................................................................. 101

5.1. Dane znakowe .................................................................................................... 101


5.1.1. Zestaw znakw ASCII ........................................................................... 101
5.1.2. Zestaw znakw EBCDIC ....................................................................... 104
5.1.3. Dwubajtowe zestawy znakw ................................................................ 105
5.1.4. Zestaw znakw Unicode ........................................................................ 106
5.2. acuchy znakowe ............................................................................................ 108
5.2.1. Formaty acuchw znakowych ............................................................. 108
5.2.2. Rodzaje acuchw statyczne, pseudodynamiczne i dynamiczne ..... 112
5.2.3. Zliczanie odwoa do acucha .............................................................. 114
5.2.4. acuchy w Delphi i Kyliksie ................................................................ 114
5.2.5. Tworzenie wasnych formatw acuchw ............................................ 115
5.3. Zbiory znakw ................................................................................................... 115
5.3.1. Zbiory znakw w formie zbioru przynalenoci .................................... 115
5.3.2. Listowa reprezentacja zbiorw znakw ................................................. 117
5.4. Definiowanie wasnego zestawu znakw ........................................................... 117
5.4.1. Tworzenie wydajnego zestawu znakw ................................................. 118
5.4.2. Grupowanie znakw odpowiadajcych cyfrom ..................................... 120
5.4.3. Grupowanie liter .................................................................................... 120
5.4.4. Porwnywanie liter ................................................................................ 122
5.4.5. Inne grupowania znakw ....................................................................... 123
5.5. Dodatkowe informacje ....................................................................................... 124

Rozdzia 6. Organizacja pamici i dostp do niej ............................................. 127


6.1. Podstawowe elementy systemu .......................................................................... 127
6.1.1. Magistrala systemowa ............................................................................ 128
6.2. Fizyczna organizacja pamici ............................................................................ 130
6.2.1. 8-bitowe magistrale danych ................................................................... 132
6.2.2. 16-bitowe magistrale danych ................................................................. 133
6.2.3. 32-bitowe magistrale danych ................................................................. 134

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

Rozdzia 7. Zoone typy danych i obiekty w pamici ....................................... 153

7.1. Typy wskanikowe ............................................................................................ 153


7.1.1. Implementacja wskanikw ................................................................... 154
7.1.2. Wskaniki i dynamiczna alokacja pamici ............................................. 155
7.1.3. Dziaania na wskanikach arytmetyka wskanikw .......................... 155
7.2. Tablice ............................................................................................................... 159
7.2.1. Deklaracje tablic .................................................................................... 160
7.2.2. Reprezentacja tablic w pamici .............................................................. 162
7.2.3. Dostp do elementw tablicy ................................................................. 163
7.2.4. Tablice wielowymiarowe ....................................................................... 164
7.3. Rekordy (struktury) ........................................................................................... 170
7.3.1. Rekordy w Pascalu i Delphi ................................................................... 170
7.3.2. Rekordy w C i C++ ................................................................................ 171
7.3.3. Rekordy w HLA ..................................................................................... 171
7.3.4. Zapis rekordw w pamici ..................................................................... 171
7.4. Unie ................................................................................................................... 174
7.4.1. Unie w C i C++ ...................................................................................... 174
7.4.2. Unie w Pascalu, Delphi i Kyliksie ......................................................... 174
7.4.3. Unie w asemblerze HLA ........................................................................ 175
7.4.4. Unie w pamici ...................................................................................... 176
7.4.5. Inne zastosowania unii ........................................................................... 176
7.5. Dodatkowe informacje ....................................................................................... 177

Rozdzia 8. Logika boolowska i projektowanie cyfrowe .................................... 179

8.1. Algebra Boolea ................................................................................................. 179


8.1.1. Operatory boolowskie ............................................................................ 179
8.1.2. Prawa algebry boolowskiej .................................................................... 180
8.1.3. Priorytety operatorw boolowskich ....................................................... 181
8.2. Funkcje logiczne i tabele prawdy ...................................................................... 182
8.3. Numery funkcji .................................................................................................. 183
8.4. Algebraiczne przeksztacanie wyrae logicznych ............................................ 185
8.5. Formy kanoniczne ............................................................................................. 186
8.5.1. Forma kanoniczna sumy termw minimalnych a tabele prawdy ............ 187
8.5.2. Algebraiczne wyprowadzanie formy kanonicznej
sumy termw minimalnych .................................................................... 189
8.5.3. Forma kanoniczna jako iloczyn termw maksymalnych ........................ 189
8.6. Upraszczanie funkcji logicznych ....................................................................... 190
8.7. Ale co to wszystko ma wsplnego z komputerami? .......................................... 197
8.7.1. Rwnowano ukadw elektronicznych i funkcji logicznych ............. 198
8.7.2. Obwody zoone .................................................................................... 199
8.7.3. Sterowanie sekwencyjne i zegarowe ...................................................... 204
8.8. Dodatkowe informacje ....................................................................................... 208

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Rozdzia 9. Architektura procesora ................................................................. 209


9.1. Podstawy budowy procesora ............................................................................. 209
9.2. Dekodowanie i wykonywanie instrukcji logika przypadku a mikrokod ....... 211
9.3. Wykonywanie instrukcji krok po kroku ............................................................. 213
9.3.1. Instrukcja mov ....................................................................................... 213
9.3.2. Instrukcja add ......................................................................................... 215
9.3.3. Instrukcja jnz .......................................................................................... 217
9.3.4. Instrukcja loop ....................................................................................... 218
9.4. Rwnolego klucz do przyspieszenia ......................................................... 218
9.4.1. Kolejka wstpnego pobrania .................................................................. 222
9.4.2. Okolicznoci ograniczajce wydajno kolejki wstpnego pobrania ..... 225
9.4.3. Potoki jednoczesne wykonywanie wielu instrukcji ........................... 226
9.4.4. Bufory instrukcji wiele drg do pamici ........................................... 230
9.4.5. Zagroenia zwizane z potokami ........................................................... 231
9.4.6. Dziaanie superskalarne rwnolege wykonywanie instrukcji ........... 233
9.4.7. Wykonywanie kodu bez zachowania kolejnoci .................................... 235
9.4.8. Zmiana nazw rejestrw .......................................................................... 235
9.4.9. Architektura z bardzo dugim sowem instrukcji (VLIW) ...................... 236
9.4.10. Przetwarzanie rwnolege ...................................................................... 237
9.4.11. Wieloprocesorowo .............................................................................. 238
9.5. Dodatkowe informacje ....................................................................................... 239

Rozdzia 10. Konstrukcja zbioru instrukcji ......................................................... 241


10.1. Dlaczego projekt zbioru instrukcji jest wany ................................................... 241
10.2. Podstawowe cele projektowe zestawu instrukcji ............................................... 243
10.2.1. Dobr dugoci kodu instrukcji .............................................................. 245
10.2.2. Plany na przyszo ................................................................................ 247
10.2.3. Dobr instrukcji ..................................................................................... 247
10.2.4. Przypisywanie instrukcjom kodw ........................................................ 248
10.3. Hipotetyczny procesor Y86 ............................................................................... 248
10.3.1. Ograniczenia Y86 .................................................................................. 249
10.3.2. Instrukcje Y86 ........................................................................................ 249
10.3.3. Tryby adresowania Y86 ......................................................................... 251
10.3.4. Kodowanie instrukcji Y86 ..................................................................... 252
10.3.5. Przykady kodowania instrukcji Y86 ..................................................... 254
10.3.6. Rozszerzanie zbioru instrukcji Y86 ....................................................... 257
10.4. Kodowanie instrukcji 80x86 .............................................................................. 259
10.4.1. Kodowanie operandw instrukcji .......................................................... 260
10.4.2. Kodowanie instrukcji add kilka przykadw ..................................... 266
10.4.3. Stae jako operandy ................................................................................ 268
10.4.4. Kodowanie operandw 8-, 16- i 32-bitowych ........................................ 269
10.4.5. Alternatywne kodowanie instrukcji ....................................................... 270
10.5. Znaczenie projektu zbioru instrukcji dla programisty ........................................ 270
10.6. Wicej informacji .............................................................................................. 271

Rozdzia 11. Architektura pamici i jej organizacja ............................................ 273


11.1. Hierarchia pamici ....................................................................................................273
11.2. Jak dziaa hierarchia pamici ....................................................................................276
11.3. Wzgldna wydajno podsystemw pamici ..........................................................277
11.4. Budowa pamici podrcznej ....................................................................................279
11.4.1. Pami odwzorowywana bezporednio ..........................................................280
11.4.2. Pami w peni powizana ..............................................................................281
11.4.3. Pami powizana n-krotnie ...........................................................................281
11.4.4. Dobieranie schematu pamici podrcznej do rodzaju dostpu do danych ....282

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 12. Wejcie i wyjcie (I/O) ................................................................. 303


12.1. Poczenie procesora ze wiatem zewntrznym ................................................ 303
12.2. Inne sposoby czenia portu z systemem ........................................................... 306
12.3. Mechanizmy wejcia-wyjcia ............................................................................ 307
12.3.1. Odwzorowywanie w pamici ................................................................. 307
12.3.2. Wejcie-wyjcie i buforowanie .............................................................. 308
12.3.3. Odwzorowywanie na I/O ....................................................................... 308
12.3.4. Bezporedni dostp do pamici (DMA) ................................................. 309
12.4. Hierarchia szybkoci wejcia-wyjcia ............................................................... 310
12.5. Szyny systemowe i szybko transferu danych ................................................. 311
12.5.1. Wydajno magistrali PCI ..................................................................... 312
12.5.2. Wydajno magistrali ISA ..................................................................... 313
12.5.3. Magistrala AGP ..................................................................................... 313
12.6. Buforowanie ...................................................................................................... 314
12.7. Handshaking ...................................................................................................... 315
12.8. Przekroczenia czasu w porcie I/O ...................................................................... 316
12.9. Przerwania i prbkowanie I/O ........................................................................... 317
12.10. Dziaanie w trybie chronionym i sterowniki urzdze ...................................... 318
12.10.1. Sterowniki urzdze ............................................................................. 318
12.10.2. Komunikacja ze sterownikami urzdze i plikami ........................... 319
12.11. Omwienie poszczeglnych urzdze peryferyjnych ........................................ 320
12.12. Klawiatura ......................................................................................................... 320
12.13. Standardowy port rwnolegy ........................................................................... 322
12.14. Porty szeregowe ................................................................................................ 323
12.15. Stacje dyskw .................................................................................................... 324
12.15.1. Dyskietki .............................................................................................. 324
12.15.2. Dyski twarde ........................................................................................ 324
12.15.3. Systemy RAID ..................................................................................... 329
12.15.4. Napdy ZIP i inne mikkie napdy optyczne ....................................... 330
12.15.5. Napdy optyczne .................................................................................. 330
12.15.6. Napdy CD-ROM, CD-R, CD-RW,
DVD, DVD-R, DVD-RAM i DVD-RW .............................................. 331
12.16. Napdy tamowe ............................................................................................... 333
12.17. Pami flash ...................................................................................................... 334
12.18. Dyski RAM i dyski pprzewodnikowe ............................................................ 336
12.19. Urzdzenia i sterowniki SCSI ............................................................................ 337
12.20. Interfejs IDE/ATA ............................................................................................. 342

Profesjonalne programowanie. Cz 1. Zrozumie komputer


12.21. Systemy plikw na urzdzeniach pamici masowej .......................................... 344
12.21.1. Uycie mapy bitowej wolnej przestrzeni ............................................. 346
12.21.2. Tablice alokacji plikw ........................................................................ 347
12.21.3. Pliki w formie list blokw .................................................................... 350
12.22. Oprogramowanie przetwarzajce dane na urzdzeniach pamici masowej ....... 353
12.22.1. Wydajno dostpu do plikw ............................................................. 354
12.22.2. Wejcie-wyjcie synchroniczne i asynchroniczne ................................ 355
12.22.3. Znaczenie typu operacji wejcia-wyjcia ............................................. 356
12.22.4. Pliki odwzorowywane w pamici ........................................................ 356
12.23. Uniwersalna magistrala szeregowa (USB) ........................................................ 357
12.23.1. Projekt USB ......................................................................................... 358
12.23.2. Wydajno USB ................................................................................... 359
12.23.3. Rodzaje transmisji USB ....................................................................... 360
12.23.4. Sterowniki urzdze USB .................................................................... 362
12.24. Myszy, trackpady i inne urzdzenia wskazujce ............................................... 363
12.25. Joysticki i urzdzenia do gier ............................................................................ 364
12.26. Karty dwikowe ............................................................................................... 365
12.26.1. Jak dwikowe urzdzenia peryferyjne wytwarzaj dwik? .............. 366
12.26.2. Formaty audio i pliki MIDI .................................................................. 368
12.26.3. Programowanie urzdze audio ........................................................... 369
12.27. Dalsze informacje .............................................................................................. 369

Myl lokalnie, pisz globalnie .......................................................... 371


Dodatek A Zestaw znakw ASCII ................................................................... 373
Skorowidz ..................................................................................... 377

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.

5.1. Dane znakowe


Wikszo systemw do kodowania rnych znakw wykorzystuje pojedyncze bajty
lub pary bajtw. Dotyczy to take systemw Windows i Linux wykorzystujcych zestawy znakw ASCII lub Unicode, gdzie znaki zapisuje si w pojedynczym bajcie lub
w dwubajtowym cigu. Zestaw znakw EBCDIC uywany w maszynach IBM mainframe i w minikomputerach to kolejny przykad jednobajtowego kodu znakw.
Omwimy tutaj wszystkie trzy zestawy znakw i ich zapis wewntrzny. Powiemy te,
jak stworzy wasny, dostosowany do specyficznych potrzeb zestaw znakw.

5.1.1. Zestaw znakw ASCII


Zestaw znakw ASCII (skrt od ang. American Standard Code for Information Interchange Amerykaski Kod Standardowy Wymiany Informacji) odwzorowuje 128
znakw na liczby cakowite bez znaku od 0 do 127 ($0..$7F). Wprawdzie dokadny

102

Profesjonalne programowanie. Cz 1. Zrozumie komputer

sposb tego odwzorowania jest w gruncie rzeczy do przypadkowy i niezbyt istotny,


ale istnienie takiego standardu pozwala na komunikowanie si ronych programw
i urzdze peryferyjnych. Standardowe kody ASCII s przydatne, poniewa niemal
wszyscy ich uywaj. Wobec tego, jeli uyjemy kodu ASCII 65 do zapisania znaku A,
to dowolne urzdzenie peryferyjne na przykad drukarka prawidowo zinterpretuje
t warto jako liter A.
Zestaw znakw ASCII zapewnia tylko 128 rnych znakw, wic pojawia si wane
pytanie co z pozostaymi 128 wartociami ($80..$FF), ktre mona zapisa na jednym
bajcie? Odpowied brzmi: pomijamy te znaki. I tak wanie bdziemy postpowa
w niniejszej ksice. Inna moliwo to rozszerzenie zestawu ASCII o tych 128 znakw.
O ile jednak wszyscy nie bd zgodni co do dokadnego sposobu tego rozszerzenia1,
podwaony zostanie sens uywania standardowego zestawu znakw. A doprowadzenie
do zgody wszystkich to nieatwe zadanie2.
Mimo powanych niedostatkw, zestaw znakw ASCII jest standardem wymiany danych
midzy programami i komputerami. Wikszo programw potrafi odczyta dane ASCII,
a take je zapisywa. Jako e wikszo Czytelnikw zapewne w swoich programach
uywa znakw ASCII, dobrze byoby przeanalizowa ich ukad i zapamita kluczowe
znaki, takie jak 0, A, a i im podobne. W tabeli A.1 dodatku A wymieniono wszystkie
znaki z tego zestawu.
Znaki ASCII dzieli si na cztery grupy zawierajce po 32 znaki. Pierwsze 32 znaki
o kodach od $0 do $1F (od 0 do 31) to specjalny zbir znakw niedrukowalnych nazywanych znakami kontrolnymi. Nazwa ta wzia si std, e realizuj one rne funkcje
sterujce drukark i monitorem, a nie s pokazywane jako takie. Przykadami znakw
kontrolnych mog by: powrt karetki, powodujcy umieszczenie kursora na pocztku
biecego wiersza3; nowy wiersz, przenoszcy kursor wiersz niej; backspace, ktry
przesuwa kursor o jeden znak w lewo. Niestety, niektre znaki kontrolne powoduj
rne dziaania rnych urzdze wyjciowych. Standaryzacja w tym zakresie jest
bardzo niewielka. Aby mie pewno, e wiemy, co dany znak kontrolny wykonuje
w uywanym urzdzeniu, trzeba sprawdzi to w dokumentacji.
Druga grupa 32 znakw ASCII to rne symbole przestankowe, znaki specjalne i cyfry.
Najwaniejsze znaki z tej grupy to spacja (kod ASCII $20) oraz cyfry (kody $30..$39).

Zanim spopularyzowa si system Windows, produkty IBM obsugiway na wywietlaczach tekstowych


256-elementowy zestaw znakw. Chocia zestaw ten funkcjonuje obecnie nawet we wspczesnych
komputerach PC, niewiele aplikacji czy urzdze peryferyjnych nadal obsuguje te rozszerzone znaki.

Powody do niegodzenia si na stosowanie wspomnianego przez Autora zestawu znakw mamy


chociaby my, Polacy. Ot zestaw ten, znany jako ISO-Latin1 lub ISO-8859-1, nie zawiera polskich
liter, takich jak czy , i jest dostosowany do jzykw zachodnioeuropejskich. Istniej alternatywne
zestawy znakw dodatkowych, zawierajce inne znaki; wszystkie one maj takie same 128 pierwszych
znakw ASCII. Przykadowo, zestaw ISO-Latin2 (inaczej ISO-8859-2) zawiera m.in. nasze znaki
narodowe przyp. tum.

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.

Rozdzia 5. Dane znakowe

103

Trzecia grupa 32 znakw zawiera wielkie litery. Kody liter od A do Z mieszcz si


w zakresie $41..$5A. W alfabecie aciskim jest tylko 26 liter, wic pozostaych 6 znakw
zawiera rne symbole specjalne. Ostatnia grupa 32 znakw zawiera mae litery, pi
dodatkowych znakw specjalnych i jeszcze jeden znak kontrolny, delete (usuwajcy
znak spod kursora). Zwrmy uwag na to, e mae litery wykorzystuj kody ASCII
$61..$7A. Jeli zamieniamy mae litery na wielkie lub odwrotnie, rnica midzy ma
a odpowiadajc jej wielk liter to tylko jeden bit. Na rysunku 5.1 pokazano przykadowo kody liter E i e.
Rysunek 5.1.
Kody ASCII
liter E i e

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

cyfry i znaki przestankowe

wielkie litery i znaki specjalne

mae litery i znaki specjalne

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

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Tabela 5.2. Kody ASCII cyfr


Znak

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.

5.1.2. Zestaw znakw EBCDIC


Wprawdzie nie ulega wtpliwoci, e zestaw ASCII jest najpopularniejszym zestawem
znakw, ale nie jest on jedyny. Na przykad IBM na wielu swoich komputerach mainframe i minikomputerach uywa kodu EBCDIC. Kod ten pojawia si gwnie na duych
komputerach, natomiast na osobistych spotyka si go bardzo rzadko, wic powicimy
mu niewiele uwagi.
EBCDIC to skrt od angielskiego Extended Binary Coded Decimal Interchange Code,
czyli Rozszerzony kod wymiany danych dziesitnych kodowanych binarnie. Czy istnia
kiedy taki kod nierozszerzony? Owszem, kiedy w komputerach IBM i w maszynach
do dziurkowania kart uywano zestawu znakw znanego jako BCDIC. Zestaw ten by
oparty na kartach dziurkowanych i na zapisie dziesitnym (wizao si to ze stosowaniem zapisu dziesitnego w starszych urzdzeniach IBM-a).

Rozdzia 5. Dane znakowe

105

Pierwsze, co trzeba powiedzie o EBCDIC nie jest to pojedynczy zestaw znakw,


ale caa rodzina takich zestaww. Zestawy znakw EBCDIC maj wspln cz (na
przykad litery zwykle s kodowane tak samo), ale rne wersje EBCDIC (nazywane
stronami kodowymi) rnie koduj znaki przestankowe i specjalne. Na pojedynczym
bajcie liczba moliwych kodowa jest ograniczona, w rnych stronach kodowych te
same kody s uywane do zapisu rnych znakw. Jeli zatem mamy plik ze znakami
EBCDIC i mamy go zapisa jako ASCII, szybko okae si, e to nie jest wcale proste
zadanie.
Zanim w ogle zobaczymy zestaw znakw EBCDIC, musimy sobie zda spraw, e
przodek EBCDIC, czyli BCDIC, istnia na dugo przed pojawieniem si wspczesnych
komputerw. BCDIC powsta na potrzeby maszyn do dziurkowania i czytnikw kart.
EBCDIC pomylano jako proste rozszerzenie kodowania tak, aby umoliwi stosowanie
w komputerach IBM rozszerzonego zestawu znakw.
Jednak EBCDIC odziedziczy po BCDIC pewne nietypowe, dzisiaj ju archaiczne cechy.
Na przykad kodowanie liter alfabetu nie jest cige. Jest to prawdopodobnie bezporedni efekt stosowania pierwotnie kodowania dziesitnego (BCD). Pocztkowo litery
zapewne byy kodowane na kolejnych znakach. Jednak kiedy IBM rozszerzy zestaw
znakw, uyto kombinacji binarnych niewystpujcych w formacie BCD (wartoci
typu %1010..%1111). Takie wartoci binarne wystpuj midzy dwiema dotd ssiadujcymi wartociami BCD, wic niektre cigi znakw (na przykad litery) nie s
zapisywane w kodowaniu EBCDIC w sposb cigy.
Niestety, z uwagi na nietypowo zestawu znakw EBCDIC wiele powszechnie stosowanych algorytmw dziaajcych na zestawie ASCII w przypadku EBCDIC po
prostu nie dziaa. W rozdziale tym nie bdziemy zajmowali si kodowaniem EBCDIC
bardziej, ni tylko wspominajc o tym standardzie tu i wdzie. Trzeba jednak pamita, e wszystkie funkcje tego kodu maj swoje odpowiedniki w zestawie ASCII. Po
szczegowe informacje odsyam Czytelnika do dokumentacji IBM.

5.1.3. Dwubajtowe zestawy znakw


Z uwagi na ograniczenia kodowania 8-bitowego (co oznacza maksymalnie 128 znakw)
oraz na konieczno zapisania wikszej liczby znakw, w czci systemw uywa si
specjalnych kodw potrzebujcych do zapisania jednego znaku dwch bajtw. Takie
dwubajtowe zestawy znakw nie uywaj 16 bitw do zapisu kadego znaku; w wikszoci przypadkw uywany jest jeden bajt, a tylko w niektrych dwa bajty.
Typowy dwubajtowy zestaw znakw wykorzystuje standardowy zestaw ASCII z dodatkowymi znakami z zakresu $80..$FF. Niektre wartoci z tego zakresu to kody rozszerzenia informujce, e pojawi si drugi bajt. Kady bajt rozszerzenia pozwala zapisa 256 dodatkowych znakw. Majc trzy wartoci rozszerzajce, mona obsuy
maksymalnie 1021 rnych znakw. Z kadego bajta rozszerzajcego otrzymujemy
256 znakw, poza tym mamy 253 (2563) znakw w standardzie jednobajtowym
(minus trzy, gdy tyle znakw suy jako znacznik rozszerzajcy, ktry w zwizku
z tym nie powinien by liczony jako zwyky znak).

106

Profesjonalne programowanie. Cz 1. Zrozumie komputer

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.

5.1.4. Zestaw znakw Unicode


Jaki czas temu inynierowie Apple Computer i Xeroksa stwierdzili, e ich nowe
systemy z wywietlaczami mozaikowymi i czcionkami wybieranymi przez uytkownika
mog wywietli o wiele wicej ni 256 znakw naraz. Cho mona byo zastosowa
kodowania dwubajtowe, stwierdzono, e wystpuj powane problemy zwizane
z faktem, e znaki maj po dwa bajty, i poszukiwano innego rozwizania. Okaza si nim
zestaw znakw Unicode. Standard ten przyj si na caym wiecie i jest obsugiwany
przez niemale kady system komputerowy i system operacyjny (Mac OS, Windows,
Linux, Unix i wiele innych).
W Unicode do zapisu kadego znaku uywa si 16-bitowych sw, wic mona zapisa
do 65 536 rnych znakw. Jest to oczywicie o wiele, wiele wicej ni dotychczasowe
256 moliwych znakw w 8-bitowym bajcie. Mao tego, Unicode jest zgodny z ASCII.
Jeli najstarszych 9 bitw4 jest ustawionych na zero, modszych 7 to kod ze standardowego zestawu ASCII. Jeli 9 starszych bitw zawiera wartoci niezerowe, cae 16
bitw tworzy znak rozszerzony (rozszerzony wzgldem ASCII). Jeli kto si jeszcze
zastanawia, po co waciwie mamy a tyle kodw znakw, wystarczy przypomnie,
e niektre azjatyckie zestawy zawieraj ich 4096 (tyle znakw maj ich podzbiory
4

ASCII to kod 7-bitowy. Jeli najstarszych 9 bitw 16-bitowej wartoci Unicode jest zerami,
pozostaych 7 bitw to kod ASCII danego znaku.

Rozdzia 5. Dane znakowe

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.

Mona by twierdzi, e przetwarzanie acuchw Unicode za pomoc instrukcji przetwarzajcych


sowa nie powinno trwa duej ni przetwarzanie bajtw za pomoc instrukcji przetwarzajcych bajty.
Jednak zoptymalizowane funkcje przetwarzajce acuchy przetwarzaj zwykle podwjne sowa,
a nawet wiksze jednostki danych. Takie funkcje mog przetworzy jednorazowo dwukrotnie mniej
znakw Unicode ni znakw jednobajtowych, std do wykonania tej samej pracy trzeba dwukrotnie
wicej instrukcji maszynowych.

108

Profesjonalne programowanie. Cz 1. Zrozumie komputer

5.2. acuchy znakowe


acuchy znakowe s prawdopodobnie drugim najbardziej powszechnie stosowanym
typem danych, zaraz za liczbami cakowitymi. acuch znakowy to cig znakw majcy
dwa atrybuty: dugo i dane znakowe. acuchy znakowe maj te inne atrybuty, na
przykad dugo maksymaln, jak mona zapisa w danej zmiennej, czy liczb odwoa informujc, ile rnych zmiennych acuchowych odwouje si do tego samego
acucha. Wkrtce zajmiemy si tymi atrybutami i uyciem ich w programach, gdzie
opiszemy rne formaty acuchowe oraz opowiemy o moliwych dziaaniach na
acuchach.

5.2.1. Formaty acuchw znakowych


Rne jzyki rnie zapisuj acuchy. Niektre formaty acuchw wymagaj mniej
pamici, inne pozwalaj na szybsze przetwarzanie, jeszcze inne s wygodniejsze w uyciu, nastpne oferuj dodatkowe funkcje programicie i systemowi operacyjnemu. Aby
lepiej zrozumie zasady rzdzce acuchami znakowymi, dobrze jest przyjrze si
pewnym typowym sposobom ich zapisu, wystpujcym w rnych jzykach programowania wysokiego poziomu.

5.2.1.1. acuchy zakoczone zerem


Niewtpliwie acuchy zakoczone zerem s najpopularniejsz obecnie wykorzystywan form zapisu. Jest to format natywny dla jzykw C, C++, Java i innych. Poza
tym acuchy zakoczone zerem spotyka si w programach pisanych w jzykach, ktre
nie maj wasnego formatu natywnego acuchw, takich jak asemblery.
Zakoczony zerem acuch ASCII to cig zawierajcy zero lub wicej 8-bitowych
znakw, koczcy si bajtem zerowym (a w przypadku Unicode cig majcy zero
lub wicej 16-bitowycyh kodw znakw zakoczonych 16-bitowym zerowym sowem).
Na przykad w C i C++ acuch ASCII abc wymaga czterech bajtw: po jednym na
kad z liter: a, b i c oraz jednego bajta zerowego.
acuchy zakoczone zerem maj pewne zalety, ktrych pozbawione s inne formaty:
Mog zawiera praktycznie dowolnie dugie cigi znakowe, z narzutem

zaledwie jednego bajta (lub dwch bajtw w przypadku Unicode).


Z uwagi na popularno jzykw C i C++ dostpne s bardzo dobrze

zoptymalizowane biblioteki do ich obsugi.


S atwe w implementacji. Faktycznie poza przypadkiem staych literaw

acuchowych jzyki C i C++ w ogle nie zawieraj obsugi takich acuchw.


W tych jzykach s one po prostu tablicami znakowymi. Dlatego chyba
projektanci C wybrali taki wanie format nie musieli troszczy si
o wzbogacanie jzyka o operatory acuchowe.
Omawiany format pozwala zapisywa acuchy zakoczone zerem w dowolnym

jzyku umoliwiajcym tworzenie tablic znakw.

Rozdzia 5. Dane znakowe

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

przypadku. Wiele operacji acuchowych musi zna dugo acucha przed


rozpoczciem jego przetwarzania. Jedynym sposobem obliczenia dugoci
acucha zakoczonego zerem jest przejrzenie go od pocztku do koca.
Im jest on duszy, tym wolniej dziaa bdzie funkcja. Wobec tego acuchy
zakoczone zerem nie s najlepszym rozwizaniem w przypadku przetwarzania
dugich acuchw.
W ich przypadku trudno jest zapisa znak, ktrego kod jest zerem

na przykad znak ASCII NUL. Zwykle nie jest to jednak istotne.


W takim acuchu nie ma nigdzie umieszczonej informacji, jak bardzo moe

on zosta wyduony. Wobec tego w przypadku czci funkcji do obsugi


acuchw (takich jak konkatenacja) mona doj tylko do obecnego koca
zmiennej lub ewentualnie sprawdzi przepenienie, jeli jawnie zostanie
przekazana maksymalna dopuszczalna dugo.

5.2.1.2. acuchy poprzedzone dugoci


Drugi format acuchw znakowych, acuchy poprzedzone dugoci, pozwala unikn
czci problemw charakterystycznych dla acuchw zakoczonych zerem. acuchy
poprzedzone dugoci s charakterystyczne dla jzykw takich jak Pascal; skadaj
si zwykle z pojedynczego bajta okrelajcego dugo acucha, po ktrym nastpuje
zero lub wicej 8-bitowych znakw. W tym wypadku napis abc skadaby si z czterech
bajtw: dugoci acucha ($03), a nastpnie znakw a, b i c.
Dziki acuchom poprzedzonym dugoci mona unikn dwch problemw, na jakie
natknlimy si przy poprzednim formacie ich zapisu. Po pierwsze, bez problemu mona
zapisywa znak NUL. Po drugie, szybciej dziaaj operacje acuchowe. Inna ich zaleta
jest taka, e jeli spojrze na taki acuch jak na tablic znakow, dugo zwykle znajduje si na pozycji zerowej, wic indeksy samego acucha zaczynaj si od jedynki.
W przypadku wielu funkcji acuchowych indeksowanie znakw od jedynki jest znacznie
wygodniejsze ni indeksowanie od zera (jak dzieje si w acuchach zakoczonych
zerem).
acuchy poprzedzone dugoci maj te wady, z ktrych najwaniejsz jest narzucone ograniczenie dugoci do 255 znakw (o ile dugo jest zapisywana w jednym
bajcie). Mona omin to ograniczenie, zapisujc dugo na 2 lub 4 bajtach, ale wtedy
zwiksza si narzut na kady acuch.

5.2.1.3. acuchy siedmiobitowe


Ciekawy format dziaajcy na kodach 7-bitowych, takich jak ASCII, zakada uycie
najstarszego bita do oznaczenia koca acucha. Wszystkie znaki poza ostatnim w acuchu maj najstarszy bit wyzerowany (lub ustawiony, kwestia gustu), a ostatni znak
ma ten bit ustawiony (lub odwrotnie, wyzerowany).

110

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Oto wady acuchw siedmiobitowych:


Aby okreli ich dugo, trzeba je w caoci przejrze.
W tym formacie nie mona zapisa acucha o zerowej dugoci.
Niewiele jzykw programowania pozwala zapisywa stae literay jako

acuchy 7-bitowe.
Ograniczeni jestemy do 128 kodw znakw, cho w przypadku korzystania

ze zwykego ASCII nie stanowi to problemu.


Jednak ogromn zalet acuchw 7-bitowych jest to, e nie wymagaj adnego narzutu
na kodowanie dugoci. Do ich obsugi najlepszym wyborem jest asembler (przy czym
definiuje si makro do tworzenia staych literaw takich acuchw). Wynika to ze
zwartoci zapisu tych acuchw, co doceni przede wszystkim wanie programici
asemblerowi. Oto makro asemblera HLA, ktre konwertuje litera acuchowy na
acuch 7-bitowy:
#macro sbs( s );
// Pobranie wszystkich znakw acucha poza ostatnim:
(@substr( s, 0, @length(s) - 1) +
// Zczenie ostatniego znaku z ustawionym najstarszym bitem:
char( uns8( char( @substr( s, @length(s) - 1, 1))) | $80 ))
#endmacro
...
byte sbs( "Hello World" );

5.2.1.4. acuchy HLA


Pki nie przeszkadza nam kilka dodatkowych bajtw narzutu, mona stworzy format
acuchw czcych w sobie zalety acuchw poprzedzonych dugoci i zakoczonych zerem, unikajc jednoczenie wad jednych i drugich. Przykadem jest natywny
format acuchw jzyka HLA7.
Najpowaniejsz wad acuchw w formacie HLA jest duy narzut na kady acuch.
Procentowo moe on by szczeglnie istotny w rodowiskach o ograniczonych zasobach i w przypadku korzystania z wielu krtkich acuchw. acuchy HLA zawieraj
zarwno dugo przed acuchem waciwym, jak i koczcy bajt zerowy, a take inne
informacje; cznie narzut wynosi dziewi bajtw na acuch8.

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.

Rozdzia 5. Dane znakowe

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

Cztery bajty znajdujce si tu przed pierwszym znakiem acucha to faktyczna jego


dugo. Cztery poprzednie bajty to maksymalna dugo acucha. Za znakami wchodzcymi w skad tekstu znajduje si bajt zerowy. HLA gwarantuje, e caa struktura
danych acucha bdzie wielokrotnoci czterech bajtw (jest to korzystne z uwagi na
wydajno), wic na kocu takiego obiektu moe znajdowa si do trzech bajtw wypenienia (aby struktura z rysunku 5.2 miaa dugo bdc wielokrotnoci czterech
bajtw, wystarcz dwa bajty wypenienia).
Zmienne acuchowe HLA to wskaniki zawierajce adres bajta z pierwszym znakiem
acucha. Aby sign do pl okrelajcych dugo, trzeba zaadowa warto wskanika
do rejestru 32-bitowego. Do pola okrelajcego dugo sigamy, podajc offset rwny
4, a do pola okrelajcego dugo maksymaln offset rwny 8. Oto przykad:
static
s :string := "Hello World";
...
mov( s, esi );
// Do esi wstawiamy adres litery 'H'
// z napisu "Hello World"
mov( [esi-4], ecx ); // Dugo acucha wstawiamy do ECX (dla "Hello
// World" jest to 11).
...
mov( s, esi );
cmp( eax, [esi-8] ); // Sprawdzamy, czy dugo z EAX przekracza
// maksymaln dugo acucha.
ja StringOverflow;

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

Profesjonalne programowanie. Cz 1. Zrozumie komputer

5.2.1.5. acuchy z deskryptorem


Rozwaane przez nas dotd formaty acuchw miay wszystkie atrybuty acucha
(dugoci i bajty koczce) wraz z samym acuchem. By moe nieco elastyczniejszym
rozwizaniem jest trzymanie informacji o maksymalnej i biecej dugoci acucha
w strukturze zawierajcej te wskanik do danych znakowych. Takie struktury nazywamy
deskryptorami. Oto przykadowa struktura danych jzyka Pascal (lub Delphi czy Kyliksa):
type
dString :record
curLength :integer;
strData
:^char;
end;

Zauwamy, e struktura ta nie zawiera danych znakowych, ale ma wskanik strData


do pierwszego znaku acucha. Pole curLength okrela biec dugo acucha. Oczywicie, mona do takiego rekordu doda dowolnie wiele innych potrzebnych pl, na
przykad dugo maksymaln, cho ta akurat nie jest tu potrzebna; wikszo formatw
wykorzystujcych deskryptory jest dynamiczna i ogranicza si tylko do przechowywania
faktycznej dugoci.
Ciekaw cech acuchw opartych na deskryptorach jest to, e same dane zwizane z deskryptorem mog by czci duszego acucha. W danych tych nie jest
zapisywana dugo acucha ani nie s wstawiane adne bajty koczce, wic dane
znakowe dwch acuchw mog na siebie nachodzi. Spjrzmy na przykad na rysunek 5.3. Mamy tu dwa acuchy: Hello World i World. Napisy ten nachodz na
siebie. Dziki temu mona zaoszczdzi nieco pamici, poza tym niektre funkcje
(takie jak substring) mog dziaa bardzo szybko. Oczywicie, kiedy mamy do czynienia z takim zachodzeniem na siebie acuchw, jak to pokazano, nie mona modyfikowa danych acucha, gdy powodowaoby to modyfikowanie jednoczenie czci
drugiego acucha.
Rysunek 5.3.
Zachodzce
na siebie acuchy
wykorzystujce
deskryptory

5.2.2. Rodzaje acuchw statyczne,


pseudodynamiczne i dynamiczne
Wrd acuchw, ktre dotd omwilimy, moemy wyrni trzy typy, jeli podzia
w bdzie przebiega wedug tego, kiedy system alokuje pami na dane znakowe.
Chodzi o acuchy statyczne, pseudodynamiczne i dynamiczne.

Rozdzia 5. Dane znakowe

113

5.2.2.1. acuchy statyczne


acuchy statyczne to takie, w ktrych programista ustala maksymaln ich dugo
podczas pisania programu. Do tej grupy nale acuchy Pascala (i acuchy Delphi
krtkie, ang. short). Nale tu te tablice znakw zawierajce zakoczone zerem acuchy C i C++. Wemy pod uwag nastpujc deklaracj Pascala:
(* przykad statycznego acucha w Pascalu *)
var

pascalString :string(255);

// Maksymalna dugo to zawsze 255 znakw.

A oto przykad w C i C++:


// przykad statycznego acucha w C i C++:
char cString[256];

// Maksymalna dugo to zawsze 255 znakw (plus bajt zerowy).

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.

5.2.2.2. acuchy pseudodynamiczne


acuchy pseudodynamiczne to takie, ktrych dugo jest ustawiana przez system
w trakcie dziaania programu za porednictwem funkcji typu malloc alokujcych pami
na acuch. Jednak kiedy system ju pami zaalokuje, wielko maksymalna acucha
jest ustalona. Tak wanie dziaaj acuchy HLA9. Programista HLA do alokowania
pamici na zmienn acuchow zwykle uywa funkcji stralloc. Po jej wywoaniu
obiekt acuchowy ma ustalon dugo, ktra nie moe ulega zmianom10.

5.2.2.3. acuchy dynamiczne


Systemy acuchw dynamicznych, zwykle wykorzystujce format oparty na deskryptorach, automatycznie alokuj wystarczajc ilo pamici przy kadym utworzeniu
nowego acucha lub takiej modyfikacji, ktra zmienia dugo acucha ju istniejcego.
W przypadku acuchw dynamicznych operacje takie, jak przypisanie czy pobranie
czci acucha, s banalnie proste zwykle wystarczy tylko skopiowa dane z deskryptora, wic operacje te dziaaj szybko. Jednak przy korzystaniu z acuchw w ten
sposb trzeba pamita, e nie wolno danych z powrotem wstawia do tego samego
obiektu, gdy mona zmodyfikowa dane wykorzystywane te przez inny acuch.

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

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Rozwizaniem tego problemu jest wykorzystanie techniki nazywanej kopiowaniem


przy zapisie. Polega ona na tym, e kiedy trzeba zmieni co w acuchu dynamicznym,
najpierw wykonywana jest kopia tego acucha i na niej przeprowadzane s wszystkie
konieczne zmiany. Badania wykazay, e w przypadku typowych programw kopiowanie przy zapisie moe poprawi wydajno wielu aplikacji, gdy operacje takie jak
przypisanie i wybieranie podacucha s wykonywane znacznie czciej ni modyfikowanie danych wewntrz acucha. Jedyn wad tego mechanizmu jest to, e po kilku
modyfikacjach danych w pamici sterta moe zawiera nieuywane ju acuchy
znakowe. Aby unikn takich wyciekw pamici, w systemach dynamicznych acuchw
znakowych zwykle stosowane jest oczyszczanie, ktre przeszukuje obszar z danymi
acuchw znakowych, wyszukujc stare, nieuywane dane i przywracajc je pamici
pozostajcej do dyspozycji programu. Niestety, takie oczyszczanie moe dziaa powoli.

5.2.3. Zliczanie odwoa do acucha


Zastanwmy si nad sytuacj, w ktrej mamy dwa deskryptory acuchw (lub po
prostu dwa wskaniki) wskazujce te same dane w pamici. Oczywicie, nie mona
takiej pamici zwolni (czyli przeznaczy do ponownego wykorzystania), gdy jeden
ze wskanikw przestaje by uywany. Jednym (i, niestety, powszechnym) rozwizaniem jest zrzucenie odpowiedzialnoci za obsug tego typu sytuacji na programist.
W miar jednak, jak ronie stopie skomplikowania aplikacji, poleganie na programicie
czsto prowadzi do pojawiania si bdnych wskanikw, wyciekw pamici i innych
tego typu problemw. Lepszym rozwizaniem jest pozwolenie programicie na zwolnienie takiej wielokrotnie wykorzystanej pamici, z jednoczesnym wstrzymaniem fizycznego
zwolnienia do chwili zwolnienia ostatniego wskanika wskazujcego te same dane.
Do ledzenia wskanikw i zwizanych z nimi danych uywa si licznikw odwoa.
Licznik odwoa to liczba cakowita zliczajca wskaniki odwoujce si do danych
znakowych umieszczonych w pamici. Przy kadym przypisaniu adresu acucha do
jakiego wskanika licznik jest zwikszany o jeden. Przy kadym zwolnieniu ktrego
ze wskanikw licznik jest zmniejszany o jeden. Faktyczne zwolnienie pamici ma
miejsce dopiero wtedy, gdy licznik zmniejszy si do zera.
Zliczanie odwoa wietnie si sprawdza, jeli jzyk obsuguje automatycznie szczegy
zwizane z przypisywaniem acuchw. Jeli liczniki zechcemy zaimplementowa
rcznie, jedyn trudnoci bdzie zapewnienie, e licznik zostanie zwikszony zawsze
przy przypisywaniu wskanika innej zmiennej wskanikowej. Najlepiej nigdy nie przypisywa wskanikw bezporednio, ale skorzysta z funkcji lub makra aktualizujcych liczniki. Jeli licznik odwoa nie bdzie prawidowo korygowany, pojawi si
nieprawidowe wskaniki lub dojdzie do wyciekw pamici.

5.2.4. acuchy w Delphi i Kyliksie


Chocia Delphi i Kylix obsuguj krtkie acuchy zgodne z acuchami poprzedzonymi dugoci (znanymi z wczeniejszych wersji Delphi), w wersjach od 4.0
uywane s acuchy dynamiczne. Wprawdzie format ten nie zosta opublikowany
(i przez to moe ulega zmianom), ale eksperymenty z Delphi przeprowadzone przeze

Rozdzia 5. Dane znakowe

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.

5.2.5. Tworzenie wasnych formatw acuchw


Zwykle wykorzystuje si takie formaty acuchw, jakie udostpnia uywany jzyk
programowania, chyba e mamy bardzo specyficzne wymagania. Jeli tak, okazuje si,
e wikszo jzykw programowania zawiera konstrukcje umoliwiajce uytkownikom definiowanie wasnych formatw acuchowych.
Jedyny problem, na jaki moemy si natkn, to wymaganie, aby stae literay acuchowe byy zapisywane zawsze w jednym formacie. Jednak zwykle atwo mona napisa
prost funkcj konwersji, ktra zamieni takie literay na wybrany format.

5.3. Zbiory znakw


Kolejnym zoonym typem danych opartym na typie znakowym jest zbir znakw rozumiany jako pojcie matematyczne. Bycie elementem tego zbioru jest naoon na
relacj binarn. Znak albo naley do zbioru, albo nie. Nie mona w zbiorze mie wielu
kopii tego samego znaku. Pojcie cigu (kiedy znaki wystpuj w okrelonej kolejnoci,
jak w acuchu znakowym) jest zbiorom znakw obce.
W tabeli 5.3 zestawiono wybrane typowe funkcje dotyczce zbiorw znakw, aby
przybliy Czytelnikowi, jakie operacje wykonuje si na takich danych.

5.3.1. Zbiory znakw w formie zbioru przynalenoci


Zbiory znakw mona zapisywa na rne sposoby. Niektre jzyki implementuj je
jako tablice wartoci logicznych (jedna warto na jeden moliwy znak). Kada z tych
wartoci decyduje, czy odpowiadajcy jej znak jest w danym zbiorze dostpny; prawda
oznacza dostpno znaku, za fasz brak danego znaku w zestawie. Aby nie marnowa

116

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Tabela 5.3. Typowe funkcje zbioru znakw


Funkcja-operator

Opis

Przynaleno

Pozwala sprawdzi, czy dany znak naley do zbioru (zwraca prawd lub fasz).

Przecicie

Zwraca przecicie dwch zbiorw znakw (czyli zbir skadajcy si


ze znakw nalecych do obu zbiorw pierwotnych).

Suma

Zwraca sum dwch zbiorw znakw (czyli wszystkie znaki bdce


elementami jednego lub obu zbiorw pierwotnych).

Rnica

Zwraca rnic dwch zbiorw (czyli znaki nalece do jednego ze zbiorw,


ale nie do drugiego).

Pobranie

Pobiera ze zbioru pojedynczy znak.

Podzbir

Zwraca prawd, jeli jeden zbir znakw jest podzbiorem drugiego.

Podzbir waciwy

Zwraca prawd, jeli jeden zbir znakw jest podzbiorem waciwym drugiego.

Nadzbir

Zwraca prawd, jeli jeden zbir znakw jest nadzbiorem drugiego.

Nadzbir waciwy

Zwraca prawd, jeli jeden zbir znakw jest nadzbiorem waciwym drugiego.

Rwno

Zwraca prawd, jeli jeden zbir znakw jest rwny drugiemu.

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.

Rozdzia 5. Dane znakowe

117

5.3.2. Listowa reprezentacja zbiorw znakw


Czasami mapa bitowa zbioru przynalenoci nie sprawdza si. Jeli na przykad zbiory
s zawsze bardzo mae (zawieraj nie wicej jak trzy czy cztery elementy), uywanie
16 lub 32 bajtw do ich zapisu jest czystym marnotrawstwem. W przypadku bardzo
maych zbiorw zwykle najlepsz metod postpowania jest uycie list znakw11. Jeli
rzadko potrzebnych jest nam wicej ni kilka znakw, przegldanie caego acucha
w celu znalezienia potrzebnego znaku jest wystarczajcym rozwizaniem.
Poza tym, jeli nasze zbiory mog mie wiele znakw, zapis w formie zbioru przynalenoci moe by dugi (na przykad taki zapis zbioru znakw Unicode wymagaby
8192 bajtw). Z tych (i nie tylko tych) powodw zapis w formie zbioru przynalenoci
nie zawsze jest najlepszy. Wtedy z odsiecz przychodz nam zapisy w formie list.

5.4. Definiowanie wasnego


zestawu znakw
W zestawach takich, jak ASCII, EBCDIC czy Unicode waciwie nie ma nic specjalnego. Ich gwna sia tkwi w tym, e s standardami midzynarodowymi, wic bardzo
wiele systemw z nich korzysta. Jeli bdziemy trzyma si jednego z tych standardw,
bardzo prawdopodobne, e nie bdziemy mieli problemw z wymian danych z innymi.
Po to wanie tworzy si standardy kodowania.
Jednak kody te nie byy projektowane z myl o uatwieniu przetwarzania znakw.
ASCII i EBCDIC tworzono z myl o urzdzeniach, ktre dzisiaj maj warto gwnie muzealn. Zestaw ASCII mia pasowa do mechanicznych klawiatur dalekopisw,
a EBCDIC tworzono z myl o starych systemach z kartami perforowanymi. Takie
urzdzenia trudno znale dzi gdziekolwiek poza muzeum, wic ukad znakw te
nie pasuje do uywanych obecnie komputerw. Gdybymy mogli dzisiaj stworzy nowy
zestaw znakw, najprawdopodobniej znaczco rniby si on od ASCII i EBCDIC.
Zapewne miaby wiele wsplnego z uywanymi dzisiaj klawiaturami (zawieraby na
przykad kody odpowiadajce powszechnie uywanym klawiszom, jak strzaki czy
klawisze PageUp i PageDown). Kody byyby tak uoone, aby uatwi wykonywanie
typowych oblicze.
Cho zestawy znakw ASCII i EBCDIC niezbyt szybko odejd w zapomnienie, nikt
nie broni nam zdefiniowa wasnego zestawu znakw. Zestawy znakw tworzone na
potrzeby konkretnych aplikacji s jak by to powiedzie dostosowane do potrzeb
pojedynczych aplikacji, wic nie bdziemy mogli potem wymienia plikw tekstowych z innymi aplikacjami, niedostosowanymi do naszego kodowania. Jednak do
atwo zapewni translacj midzy rnymi zestawami znakw wystarczy do tego
sownik przekodowujcy. Wtedy ju prosta bdzie zamiana kodowania wewntrznego
11

Jednak w tym wypadku to na programicie spoczywa odpowiedzialno za zachowanie semantyki


zbiorw czyli nie mona dopuci do tego, aby na licie ktrykolwiek znak pojawi si wicej ni raz.

118

Profesjonalne programowanie. Cz 1. Zrozumie komputer

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.

5.4.1. Tworzenie wydajnego zestawu znakw


Podczas tworzenia nowego zestawu znakw powinnimy uwzgldni kilka spraw. Na
przykad, czy bdziemy musieli zapisywa acuchy znakowe w istniejcym formacie?
Moe to wpywa na sposb kodowania naszych acuchw. Jeli na przykad bdziemy
chcieli uywa funkcji bibliotecznych korzystajcych z acuchw zakoczonych zerem, musimy w naszym zestawie zostawi zero jako znacznik koca acucha. Trzeba
pamita te, e wiele funkcji obsugujcych acuchy nie zadziaa z naszym nowym
zestawem niezalenie od tego, jak go zdefiniujemy. Przykadowo, funkcje typu stricmp
dziaaj tylko w przypadku liter uoonych zgodnie ze standardem ASCII (lub innym
powszechnie przyjtym standardem). Wobec tego nie powinnimy tak bardzo przejmowa si istniejcym formatem, gdy wiele funkcji obsugujcych acuchy i tak

Rozdzia 5. Dane znakowe

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 (, ), [, ], {, },

< lub >).


Sprawdzanie, czy znak jest znakiem przestankowym.
Sprawdzanie, czy znak jest biaym znakiem (czyli spacj, tabulatorem

lub znakiem nowego wiersza).


Sprawdzanie, czy znak jest znakiem sterujcym kursorem.
Sprawdzanie, czy znak jest znakiem kontrolujcym ekran

(na przykad PageUp, PageDown, Home czy End).


Sprawdzanie, czy znak odpowiada klawiszowi funkcyjnemu.

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

Profesjonalne programowanie. Cz 1. Zrozumie komputer

5.4.2. Grupowanie znakw odpowiadajcych cyfrom


Wemy pod uwag pierwsze trzy funkcje z powyszej listy najatwiej bdzie nam
je realizowa, jeli znakom o kodach od 0 do 9 przypiszemy kolejne cyfry. Korzystajc z pojedynczego porwnania wartoci bez znaku, sprawdzamy, czy dany znak jest
cyfr. Konwersja midzy cyfr a jej wartoci jest banalna, gdy kod i warto znaku
s identyczne.

5.4.3. Grupowanie liter


Kolejnym typowym problemem zwizanym z obsug znakw i acuchw znakowych
jest obsuga liter. Zestaw ASCII, cho jest o niebo lepszy od EBCDIC, po prostu nie
nadaje si do sprawdzania i przetwarzania liter. Oto problemy z literami ASCII, ktre
rozwiemy w HyCode:
Litery zostay umieszczone w dwch osobnych czciach. Sprawdzanie,

czy znak jest liter, wymaga zrobienia czterech porwna.


Mae litery maj kody ASCII wiksze od wielkich liter. Jeli chodzi

o porwnania, bardziej intuicyjne jest traktowanie maych liter jako


znajdujcych si wczeniej ni wielkie.
Wszystkie mae litery maj wartoci wiksze od poszczeglnych wielkich

liter. Prowadzi to do niezgodnych z intuicj efektw, kiedy a jest wiksze


od B, cho kade dziecko wie, e jest inaczej.
Kodowanie HyCode rozwizuje te problemy na kilka ciekawych sposobw. Po pierwsze, do zapisu 52 liter uywane s kody od $4C do $7F. HyCode wykorzystuje tylko
128 znakw ($00..$7F), z czego 52 to litery. Wobec tego, jeli bdziemy sprawdza, czy
dany znak jest liter, wystarczy porwna, czy jego kod jest wikszy lub rwny $4C.
W jzykach wysokiego poziomu wystarczy porwnanie typu:
if( c >= 76) ...

Jeli kompilator bdzie obsugiwa HyCode, wystarczy zapis:


if( c >= 'a') ...

W asemblerze wystarczy wykorzysta dwie instrukcje:


cmp( al, 76 );
jnae NotAlphabetic;
// Instrukcje wykonywane dla liter.
NotAlphabetic:

Kolejna zaleta HyCode (istotnie rnica to kodowanie od innych) to przeplatanie


wielkich i maych liter (czyli kolejno zapisywane s znaki a, A, b, B, c, C i tak dalej).
Dziki temu sortowanie i porwnywanie acuchw jest bardzo atwe, niezalenie od
tego, czy uwzgldniamy wielko liter, czy nie. Przeplatanie powoduje, e najmodszy

Rozdzia 5. Dane znakowe

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;

// Uwaga: obsugujemy wartoci bez znaku!

// Kod obsugujcy mae znaki


NotLower:
// Zauwamy, e w instrukcja ROR tworzy kody z zakresu $A6..$BF bdce
// ujemnymi wartociami 8-bitowymi. S to przy okazji *najmniejsze* liczby
// ujemne, jakie ROR moe wygenerowa z zestawu znakw HyCode.
ror( 1, al );
cmp( a1, $a6 );
jge NotUpper
// Uwaga: obsugujemy wartoci bez znaku!
// Kod obsugujcy wielkie litery.
NotUpper:

Niestety, niewiele jzykw programowania zawiera odpowiednik instrukcji ror, niewiele


pozwala te traktowa znaki jako wartoci raz ze znakiem, raz bez niego. Wobec tego
pokazany kod jest w zasadzie ograniczony w zastosowaniach do programw asemblerowych.

122

Profesjonalne programowanie. Cz 1. Zrozumie komputer

5.4.4. Porwnywanie liter


Zastosowane w HyCode grupowanie liter oznacza, e kolejno sownikow moemy
uzyska prawie za darmo. Pki nie przeszkadza nam, e mae litery s mniejsze od
odpowiadajcych im wielkich, sortowanie acuchw HyCode daje kolejno sownikow. Wynika to std, e w HyCode w przeciwiestwie do ASCII zachodz nastpujce
relacje midzy literami:
a < A < b < B < c < C < d < D < ... < w < W < x < X < y < Y < z < Z

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

Oto przykad kodu 80x86 realizujcego podobne funkcje:


// Zakadamy, e c jest w cl, a d w dl
cmp( cl, 'a');
jb NotLower;

12

// Sprawdzamy, czy c jest z zakresu 'a'..'z'.

Tak naprawd w standardowej bibliotece C moe by jeszcze gorzej: obecnie biblioteki te zawieraj
tablice przekodowa odwzorowujce zakresy znakw, ktre jednak tu pominiemy.

Rozdzia 5. Dane znakowe


cmp( cl, 'z' );
ja NotLower;
and( $5f, cl);
Notlower:
cmp( dl, 'a' );
jb NotLower2;
cmp( dl, 'z' );
ja NotLower2;
and( $5f, dl );
Notlower2:
cmp( cl, dl );
jne NotEqual;

123

//Konwersja maych liter z c1 na wielkie

// Sprawdzamy, czy d jest w zakresie 'a'..'z'

// Konwersja maego znaku z dl na wielki.

// Porwnanie znakw (jeli byy to litery,


// teraz s wielkimi literami).
// Pomijamy kod obsugujcy c==d, gdy c i d nie s
// sobie rwne.

// Kod obsugujcy c==d bez uwzgldniania wielkoci liter.


NotEqual:

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;

// Jeli CL < 76 ('a'), nie jest to litera, wic oba


// znaki na pewno nie s sobie rwne nawet pomijajc
// wielko liter.

or( 1, cl );
or( 1, dl );

// CL to litera niech bdzie wielka.


// DL moe zawiera liter lub nie. Wymuszamy jej zamian
// na wielk.

TestEqual:
cmp( cl, dl );
jb TestEqual;

// Porwnanie wielkich wersji przekazanych znakw. Jeli


// nie s sobie rwne, odrzucamy je.

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.

5.4.5. Inne grupowania znakw


Skoro na jednym kocu zakresu znakw s litery, a na drugim cyfry, sprawdzenie, czy
znak jest alfanumeryczny, wymaga dwch porwna (to i tak lepiej ni cztery porwnania konieczne w ASCII). Oto kod Pascala (Delphi, Kyliksa) do sprawdzania, czy znak
jest alfanumeryczny:
if( ch < chr(10) or ch >= chr(76)) then ...

124

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Istniej programy i to nie tylko kompilatory ktre musz skutecznie przetwarza


acuchy znakw bdce identyfikatorami. W wikszoci jzykw w identyfikatorach
mog wystpowa znaki alfanumeryczne; my do ich identyfikacji potrzebujemy dwch
porwna.
W wielu jzykach w identyfikatorach mog wystpowa take podkrelenia, a czasami (na przykad w MASM i TASM) inne znaki, jak mapa (@) czy znak dolara ($).
Wobec tego podkreleniu przypiszemy warto 75, dolarowi i mapie kody 73 i 74
dziki temu nadal znaki wystpujce w identyfikatorach bdziemy mogli wskaza
po dwch porwnaniach.
Z podobnych powodw w HyCode zgrupowano kilka innych klas znakw w cige
obszary. Na przykad zgrupowane s klawisze sterujce kursorem, biae znaki, nawiasy
(okrge, kwadratowe, klamrowe i trjktne), operatory arytmetyczne, znaki przestankowe i tak dalej. W tabeli 5.4 przedstawiono kompletny zestaw znakw HyCode.
Analizujc kody liczbowe poszczeglnych znakw, zauwaymy, e te kody pozwalaj
sprawnie wykonywa wikszo opisanych wczeniej funkcji.

5.5. Dodatkowe informacje


ASCII, EBCDIC i Unicode to standardy midzynarodowe. Wicej informacji o rodzinie
zestaww znakw EBCDIC znale mona na witrynie firmy IBM, http://www.ibm.com.
ASCII i Unicode to standardy ISO i jako takie s udokumentowane przez ISO. W zasadzie dokumentacja ta jest patna, ale mnstwo informacji o zestawach znakw ASCII
i Unicode mona znale, podajc ich nazwy w wyszukiwarce internetowej. O Unicode
mona te poczyta na witrynie http://www.unicode.org.
Osoby zainteresowane szerszym opisem znakw, acuchw, zestaww znakw i funkcji
do obsugi tych struktur powinny zajrze do dokumentacji nastpujcych jzykw:
Jzyk programowania awk.
Jzyk programowania Perl.
Jzyk programowania SNOBOL4.
Jzyk programowania Icon.
Jzyk programowania SETL.
Asembler HLA.

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.

Rozdzia 5. Dane znakowe

125

Tabela 5.4. Zestaw znakw HyCode


Binarnie

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

Profesjonalne programowanie. Cz 1. Zrozumie komputer

Tabela 5.4. Zestaw znakw HyCode cig dalszy


Binarnie

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

You might also like