Professional Documents
Culture Documents
Kod wynikowy
V.
83
Kod wynikowy
Niniejszy rozdzia rni si troch od reszty ksiki. Rozwaania w nim zawarte
"le na niszym poziomie abstrakcji", nie dotycz bowiem skadni ani bibliotek
jzyka C lecz procesu powstawania programu wynikowego i sposobw ingerencji
w ten proces. Podczas gdy w pozostaych rozdziaach staraem si opisywa jzyk
C w sposb niezaleny zarwno od kompilatora jak i sprztu, ten rozdzia bdzie
dotyczy tylko komputerw kompatybilnych z IBM PC, pracujcych pod nadzorem systemu DOS.
Kady, kto zetkn si z jzykiem C, zastanawia si zapewne, dlaczego najprostszy program:
main()
{}
daje tak duy kod wynikowy. Ot dzieje si tak nie dlatego, e kompilatory C
daj bardzo nieoptymalny kod, tylko dlatego, e bardzo powanie traktuj kady
program. W wyniku takiego powanego podejcia, do kadego programu doczany jest spory fragment kodu (w dalszej czci rozdziau bd okrela go mianem
Startup), ktry po pierwsze przygotowuje pewne dane dla programu gwnego
a po drugie robi wszystko co moliwe, eby zabezpieczy system przed zmianami
jakie moe poczyni program. Startup zachowuje szereg informacji o stanie systemu w chwili uruchomienia programu: adres zmiennych rodowiskowych, wersj
DOS-u, wektory niektrych przerwa, itp. Kolejn wykonywan czynnoci jest
przygotowanie pewnych danych i funkcji wykorzystywanych przez program
gwny. Instalowana jest na przykad standardowa funkcja obsugi bdu dzielenia
przez zero, funkcje arytmetyki zmiennoprzecinkowej, zapamitywana jest warto
zegara BIOS-u w celu ewentualnego uycia przez funkcj clock.
Jedn z waniejszych funkcji wykonywanych przez Startup jest przygotowanie
argumentw dla funkcji main. Funkcja ta moe mie trzy argumenty:
main(int argc, char *argv[], char *envp[])
Oczywicie, nie kady program musi uywa argumentw, a nie kady, ktry ich
uywa, musi uywa wszystkich. Poprawne s rwnie nastpujce nagwki
funkcji main:
main()
main(int argc)
main(int argc,char *argv[])
W pierwszym argumencie, oznaczonym tutaj argc, Startup przekazuje do programu gwnego liczb argumentw w wierszu wywoania programu plus jeden.
Drugi argument, oznaczony argv, jest wskanikiem do tablicy wskanikw wskazujcych kolejne argumenty wywoania. Na przykad, jeeli program zosta wywoany w nastpujcy sposb:
84
Wgb jzyka C
program -u book a:\*.c b:\*.c
Po wykonaniu wszystkich opisanych czynnoci, Startup wywouje program gwny, czyli funkcj main. Po powrocie z funkcji main, czyli po zakoczeniu dziaania programu, Startup odtwarza zapamitane przed wywoaniem programu
informacje (na przykad wektory przerwa) i wraca do DOS-u.
1. Zmieniamy Startup
Czsto pisze si proste programu, nie wymagajce zachowywania wektorw przerwa, instalowania procedur obsugi bdw i wykonywania wszystkich tych operacji, ktre robi Startup. Chcielibymy, eby takie programy byy krtkie a mog
one by krtkie, a nawet bardzo krtkie. eby tak si stao, trzeba pozby si
zbdnego kodu, a wic trzeba usun oryginalny Startup.
Sprbujmy stworzy wasn wersj Startup-u, ktra bdzie ograniczaa si jedynie do
wywoania funkcji main, umoliwiaa zrobienie z prostego programu maego
COM-a.
W tym miejscu trzeba kilka sw powici sposobowi w jaki kompilator
(i konsolidator) doczaj Startup do programu.
W przypadku kompilatorw firmy Borland jest to realizowane w sposb bardzo
prosty i przejrzysty. Kod Startup zawarty jest w osobnych plikach o nazwach
c0?.obj (? symbolizuje tu liter oznaczajc model pamici np. s - model
small). Dla kadego modelu pamici istnieje osobny kod Startup i osobny modu
c0?.obj.
V. Kod wynikowy
85
86
Wgb jzyka C
mik taki jest przydatny np. gdy mamy uszkodzony port LPT1 i chcemy "podstawi" go portem LPT2.
/* plik lptport.c */
int _acrtused=0;
void main()
LPT2 */
{
int x;
x=*(int far *)0x408;
/* 40h:08h adres
LPT1 */
*(int far *)0x408=*(int far *)0x40A; /*
40h:0Ah adres LPT2 */
*(int far *)0x40A=x;
}
Program zamienia ze sob adresy portw drukarki umieszczone w obszarze danych BIOS-u. Zamy, e program znajduje si w pliku lptport.c. Po skompilowaniu w modelu Small1) otrzymamy modu lptport.obj.
Moemy teraz utworzy program wykonywalny:
tlink /t c0.obj lptport.obj , lptport.com
W biecym katalogu zostanie utworzony program LPTPORT.COM . Jego dugo w zalenoci od kompilatora i ustawionych opcji wyniesie okoo 50 bajtw!
Wprawdzie nie robi on wiele, ale ten sam program skompilowany "standardowo"
zajmuje przecie prawie 4 tysice bajtw.
Nastpny programik bdzie suy do wyboru opcji w programach wsadowych
(typu .bat). Bdzie on pobiera z klawiatury odpowied na zadane pytanie
i zwraca odpowiedni warto. Warto zwracan przez program mona
w programach wsadowych testowa przy pomocy warunku:
if ERRORLEVEL liczba
Warunek ten jest speniony, gdy warto zwrcona przez ostatnio wywoany
program jest rwna lub wiksza od wartoci liczba.
Poniewa funkcje obsugi wejcia w standardowych bibliotekach C s do obszerne, bdziemy czyta klawiatur bezporednio przy pomocy funkcji BIOS-u.
Odpowiedni do naszego programu bdzie funkcja 0 przerwania 16h. Funkcj
Wszystkie programy naley kompilowa bez informacji dla debuggera, a w kompilatorach firmy Microsoft z opcj /Gs
V. Kod wynikowy
87
public __getch
end
/* pobierz znak z
/* w przeciwnym razie
lub
link /NOE c0.obj getch tak_nie , tak_nie , , slibce
exe2bin tak_nie.exe
88
Wgb jzyka C
@echo "Zainstalowa cache-a (t/n) ? "
@tak_nie
@if ERRORLEVEL 116 SUPERPCK /EP /T+
2. Programy rezydentne
W rozdziale tym zaprezentuj "zastpczy" Startup, ktry nie bdzie, jak poprzednio, uproszczeniem Startup-a oryginalnego, lecz bdzie peni cakowicie
odmienn funkcj. Zamiast uruchamia program gwny (funkcj main), bdzie
on instalowa go jako program rezydentny, przechwytujcy wybrane przerwanie.
W ten sposb zamienienie zwykego programu na program rezydentny bdzie bardzo proste i bdzie sprowadza si do jego powtrnej konsolidacji.
Zanim przejd do meritum, chciabym przypomnie po krtce czym s programy
rezydentne, do czego su i jak si je tworzy.
Programy rezydentne to programy, ktre po zakoczeniu dziaania pozostawiaj
cz swojego kodu w pamici i ustawiaj wektor wybranego przerwania tak,
eby wskazywa na ten kod. Po wygenerowaniu tego przerwania nastpuje uruchomienie rezydujcej w pamici czci programu.
2.1. Jakie s zastosowania programw rezydentnych ?
Program rezydentny moe by rozszerzeniem systemu operacyjnego, dostarczajcym
innym programom usug, ktrych nie zapewnia system. Przykadem takiego programu jest sterownik myszki. Programy, ktre chc skorzysta z myszki (np. odczyta
pooenie kursora myszki, stan klawiszy) wywouj przy pomocy odpowiedniego
przerwania rezydentny program sterownika myszki i przekazuj mu w rejestrach
procesora informacj o jak usug prosz.
Innym zastosowaniem programw rezydentnych jest zmiana obsugi standardowego przerwania. Program taki moe na przykad przej przerwanie klawiatury
w celu niestandardowej interpretacji niektrych klawiszy (np. ALT+A jako ).
Przy pomocy programw rezydentnych realizuje si take w systemie DOS namiastk procesw dziaajcych w tle. Program przejmuje w tym celu jakie czsto wywoywane przez system przerwanie (np. przerwanie zegara 1Ch lub
przerwanie obsugi klawiatury 16h), dziki czemu jest odpowiednio czsto wywoywany. Takie "procesy" mog albo wykonywa w tle jak prost prac albo
tylko czuwa i ujawnia si dopiero po zaistnieniu okrelonego warunku (upywie okrelonego czasu, naciniciu jakiego klawisza itp.).
V. Kod wynikowy
89
90
Wgb jzyka C
samym segmencie co kod a wic do rejestrw DS oraz ES naley przed wywoaniem funkcji _main przepisa zawarto rejestru CS.
Poniej przedstawiam fragment kodu, realizujcy wszystkie opisane powyej dziaania.
Interrupt16
proc
cli
far
cmp
je
mov
sti
push
push
push
push
push
push
push
push
push
push
cs:TSR, 1
end
cs:TSR, 1
ax
bx
cx
dx
di
si
ds
es
bp
cs
pop
push
pop
ds
cs
es
wskanik
; aktywnoci nie jest ustawiony
; czy program aktywny ?
; ustaw wskanik aktywnoci
; mona odblokowa przerwania
; zachowaj rejestry na stosie
danych
aktywnoci
end:
call _main
pop
pop
pop
pop
pop
pop
pop
pop
pop
bp
es
ds
si
di
dx
cx
bx
ax
mov
cs:TSR, 0
; wyzeruj wskanik
sti
jmp
cs:Original16
; skocz do oryginalnej
procedury
endp
V. Kod wynikowy
91
ax, 3516h
;pobierz wektor 16h
21h
word ptr Original16, bx
;zachowaj offset wektora
word ptr Original16+2, es ;zachowaj segment wektora
ax, 2516h
dx, offset Interrupt16
int
21h
ax, 3100h
dx,_size
int
21h
bx,2Ch
ax,[word ptr bx]
es,ax
ah,49h
21h
Drugim zadaniem kodu startowego bdzie wypisanie wizytwki programu rezydentnego w czasie jego instalacji. Zamy, e bdzie to acuch wskazywany
przez globaln zmienn programu w C o nazwie autor. Do wypisania tego acucha uyjemy funkcji 09h DOS-u (funkcja ta oczekuje, e acuch bdzie zakoczony znakiem $).
mov
ah,09h
92
Wgb jzyka C
mov
int
;wypisz acuch
Oto pena wersja Startup-a instalujcego funkcj main jako program rezydentny
przechwytujcy przerwanie 16h :
; plik TSR16.asm
extrn _main:near
extrn _size:word
extrn _autor:near
.model TINY
.CODE
org 100h
Start:
;--- zachowaj oryginalny wektor przerwania 16h
mov
int
mov
mov
ax, 3516h
;funkcja 35h i wektor 16h
21h
word ptr Original16, bx
;zachowaj offset wektora
word ptr Original16+2, es ;zachowaj segment wektora
ax, 2516h
dx, offset Interrupt16
int
21h
ah,09h
dx,[word PTR _autor]
21h
;wypisz acuch
bx,2Ch
ax,[word ptr bx]
es,ax
ah,49h
21h
ax, 3100h
dx,_size
21h
Interrupt16 proc
cli
cmp
je
mov
sti
push
push
push
push
push
push
push
far
; zablokuj przerwania dopki wskanik
; aktywnoci nie jest ustawiony
cs:TSR, 1 ; czy aktywny ?
end
cs:TSR, 1 ; ustaw wskanik aktywnoci
; mona odblokowa przerwania
ax
; rejestry na stos
bx
cx
dx
di
si
ds
V. Kod wynikowy
93
push
push
es
bp
push
cs
pop
push
pop
ds
cs
es
call
_main
pop
pop
pop
pop
pop
pop
pop
pop
pop
bp
es
ds
si
di
dx
cx
bx
ax
mov
cs:TSR, 0
; zaznacz, e nieaktywny
sti
jmp
cs:Original16
danych
end:
; skocz do oryginalnej
procedury
endp
TSR
Original16
;offset
;segment
END Start
94
Wgb jzyka C
@echo Syntax : tsr 1c|16|9 plik.obj [ pliki.obj ]
@goto koniec
:16
link /NOE tsr16 %2 %3 %4 %5 %6 %7 %8 %9, %2 , , slibce.lib
@goto end
:1c
link /NOE tsr1c %2 %3 %4 %5 %6 %7 %8 %9, %2 , , slibce.lib
@goto end
:9
link /NOE tsr9 %2 %3 %4 %5 %6 %7 %8 %9, %2 , , slibce.lib
@goto end
:end
exe2bin %2
:koniec
REM program TSRTC.BAT dla rodowiska Turbo C
@if %1==1c goto 1c
@if %1==16 goto 16
@if %1==9 goto 9
@echo Syntax : tsr 1c|16|9 plik.obj [ pliki.obj ]
@goto end
:16
tlink /t tsr16 %2 %3 %4 %5 %6 %7 %8 %9 , %2 , , cs.lib
@goto end
:1c
tlink /t tsr1c %2 %3 %4 %5 %6 %7 %8 %9 , %2 , , cs.lib
@goto end
:9
tlink /t tsr9 %2 %3 %4 %5 %6 %7 %8 %9 , %2 , , cs.lib
@goto end
:end
W ten sposb powstanie program typu COM (uyto opcji /t programu TLINK)
o nazwie program.com. Po uruchomieniu tego programu na ekranie zostanie
wypisany komunikat przypisany zdefiniowanej w programie zmiennej globalnej
autor, a program zostanie zainstalowany w pamici jako program rezydentny wywoywany przerwaniem 16h. Od tego momentu kade wygenerowaniu przerwania
16h spowoduje wywoanie funkcji main programu.
V. Kod wynikowy
95
public _checkch
end
96
Wgb jzyka C
W trybie o numerze 7, odpowiadajcym kartom monochromatycznym, pami
ekranu zaczyna si od adresu 0xb000:0000; w pozostaych trybach - od adresu
0xb800:0000
Jeeli program rezydentny ma peni funkcj procesu dziaajcego w tle, naley
take zadba by by on wystarczajco szybki i nie spowalnia pracy komputera.
Przykad pierwszy
Z takimi zaoeniami moemy napisa pierwszy, prosty program rezydentny. Jak
przystao na ksik powicon jzykowi C, program bdzie pomocny przy
programowaniu w tym jzyku. Bdzie to nakadka na edytor, podwietlajca
sowa kluczowe jzyka C w tekcie wywietlanym na ekranie. Program, wykorzystujcy przerwanie zegarowe 1Ch bdzie regularnie przeglda ekran
w poszukiwaniu sw kluczowych C, a w przypadku znalezienia takiego sowa
bdzie odpowiednio zmienia atrybuty ekranu.
Zacznijmy od definicji globalnych. Dla potrzeb kodu startowego musimy zdefiniowa zmienn size, okrelajc rozmiar programu w paragrafach i zmienn autor, wskazujc na acuch wywietlany podczas instalacji.
int size=0x50;
char *autor="Adam Sapek
C Key Words$";
V. Kod wynikowy
97
"unsigned","static","sizeof","long","short",
"auto","register","typedef",0},**list;
inteligencja;
98
Wgb jzyka C
_acrtused=0;
Microsoft C */
/* potrzebne przy
V. Kod wynikowy
99
list++;
sowo z listy */
}
}
}
}
}
/* sprawdz nastpne
Przykad drugi
Poprzedni program naley do klasy "rezydentw" wykonujcych w tle jak prac. Inn kategori s programy "czuwajce", ktre uaktywniaj si tylko
w konkretnej sytuacji. Bardzo czsto powodem uaktywnienia programu rezydentnego jest nacinicie jakiego klawisza. W takim przypadku istnieje dwie
moliwoci: program moe przechwyci przerwanie sprztowe klawiatury 09h
lub przerwanie BIOS-u 16h.
Przerwanie 09h jest przerwaniem sprztowym, generowanym zawsze przy naciniciu (i puszczeniu) klawisza. Standardowa procedura obsugi tego przerwania
sprawdza, ktry klawisz zosta nacinity i wpisuje kod odpowiedniego znaku do
bufora klawiatury.
Z kolei przerwanie 16h jest przerwaniem programowym. Procedura obsugi tego
przerwania realizuje midzy innymi funkcje pobierania danych wprowadzanych
z klawiatury. W przeciwiestwie do obsugi wyprowadzenia danych na ekran,
gdzie BIOS jest czsto omijany a programy odwouj si bezporednio do pamici video, zdecydowana wikszo (praktycznie wszystkie) programy realizuj odczytywanie klawiatury przy uyciu funkcji przerwania 16h. Funkcje
przerwania 16h umoliwiaj sprawdzenie, czy w buforze klawiatury znajduje si
jaki znak i pobranie znaku z bufora. Jeeli funkcja pobierajca znak zostanie
wywoana gdy bufor jest pusty, to bdzie ona czekaa na wprowadzenie znaku
z klawiatury. atwo sobie wyobrazi, e gdyby programy, chcc pobra znak
z klawiatury, wywoyway od razu funkcj pobrania znaku, to instalowanie programu rezydentnego wykorzystujcego przerwanie 16h byoby pozbawione sensu. Na szczcie, powszechnie przestrzegana jest zasada, e najpierw w ptli
wywouje si funkcj sprawdzajc, czy w buforze klawiatury jest znak do pobrania, a dopiero po pojawieniu si znaku pobiera si go funkcj 00h. Dziki te-
100
Wgb jzyka C
mu moemy by prawie pewni, e przerwanie 16h bdzie wywoywane dosy
regularnie.
Wrmy do wyboru przerwania dla programu uaktywnianego naciniciem klawisza. Uwaam, e zawsze, gdy to jest moliwe, naley unika przejmowania
przerwa sprztowych. Moliwo uruchomienia w kadej chwili programu
"podwieszonego" pod takie przerwanie w wikszoci przypadkw jest wad,
a nie zalet. W praktyce, program wykorzystujcy przerwanie 16h nie zostanie
wywoany tylko w czasie trwania operacji dyskowych. Uaktywnienie programu
w takiej chwili jest raczej niepodane, gdy niepotrzebnie zwiksza ryzyko
utraty danych (zwiksza si prawdopodobiestwo wystpienia awarii, gdy plik
nie jest cakowicie zapisany). Istniej oczywicie sytuacje, w ktrych trzeba wykorzysta przerwanie sprztowe. Miaem okazj kiedy pisa program rezydentny, bdcy nakadk na pewien nieprofesjonalny program. "Rezydent" mia
umoliwia wpisywanie czsto powtarzajcych si danych przy pomocy nacinicia jednego klawisza. Po napisaniu programu okazao si, e wsppracuje
on ze wszystkim z wyjtkiem programu, dla ktrego by przeznaczony. Powodem by fakt, e program ten nie wywoywa funkcji sprawdzajcej w buforze
obecno znaku, lecz od razu pobiera ten znak. W ten sposb znaki wpisywane
z klawiatury byy od razu odczytywane z bufora przez funkcj czytajc, ktra
na nie cay czas czekaa, za program rezydentny nie mia szans na "zauwaenie"
adnego znaku. Po zamianie przerwania 16h na przerwanie sprztowe klawiatury
09h programy wsppracoway bez zarzutu.
Instalujc program korzystajcy z przerwania klawiatury trzeba pamita, e
moe on zosta wywoany w dowolnym momencie, a wic take z wntrza
DOS-u. Wywoanie programu wykorzystujcego funkcje usugowe DOS-u
(przerwanie 21h) w trakcie wykonywania ktrej z nich spowoduje najprawdopodobniej zaamanie systemu. Jednym ze sposobw zabezpieczenia si przed tak sytuacj, jest sprawdzanie przed uruchomieniem programu rezydujcego, czy
wykonywana jest jaka funkcja DOS-u. Wykorzystuje si do tego wewntrzny
znacznik DOS-u InDOS, ktrego adres zwraca funkcja 34h w rejestrach ES:BX.
Warto tego znacznika rwna zero oznacza, e nie jest wykonywana adna funkcja DOS-u. Znacznik InDOS jest ustawiony take wtedy, gdy DOS, nic nie robic,
czeka na nacinicie klawisza. Poniewa system znajduje si wwczas w jaowej
ptli, uruchomienie programu rezydentnego nie moe mu zaszkodzi. Aby umoliwi wywoanie programu w takiej sytuacji, wykorzystuje si przerwanie 28h, generowane przez system w trakcie oczekiwania na wprowadzenie danych
z klawiatury.
Zasygnalizowane powyej problemy zwizane z uruchamianiem programw rezydentnych, szczeglnie wykorzystujcych przerwanie 09h, s bardzo rozlegym
zagadnieniem. Po wyczerpujce informacje radz sign do specjalistycznej literatury dotyczcej systemu DOS.
Program, ktry poniej przedstawi, nie bdzie uaktywnia si po naciniciu
klawisza, a mimo to bdzie stale czyta klawiatur i bdzie wywoywany prze-
V. Kod wynikowy
101
rwaniem 16h. Jego zadaniem jest wygaszenie ekranu jeeli przez trzy minuty nie
zostanie nacinity aden klawisz. Program ten bdzie korzysta z kilku funkcji
napisanych w asemblerze (w tym ze zdefiniowanych wczeniej w tym rozdziale
funkcji _getch i checkch), a take ze standardowych funkcji C.
Wygaszenie ekranu moe polega na wpisaniu odpowiednich wartoci do obszaru pamici video, natomiast do wygaszenia kursora konieczne jest skorzystanie
z funkcji BIOS-u.
Poniej przedstawiam definicje dwch funkcji sucych do wygaszenia
i wywietlania kursora.
; plik kursor.asm
.MODEL SMALL
.CODE
proc _hide_cursor
mov ah,03h
mov bh,0h
int 10h
or
ch,20h
"niewidoczny"
mov ah,1h
int 10h
ret
endp
proc _show_cursor
; funkcja pokazuje kursor
mov ah,03h
mov bh,0h
int 10h
; pobierz opis kursora
and ch,0dfh
; kasuj atrybut "niewidoczny"
mov ah,1h
int 10h
; zapisz opis kursora
ret
endp
public _show_cursor, _hide_cursor
end
102
Wgb jzyka C
Wzmiankowaem wczeniej, e wiele funkcji standardowych daje zbyt dugi kod
jak na programy rezydentne. Nie dotyczy to jednak wszystkich funkcji. Jeeli
istnieje potrzeba zastosowania funkcji bibliotecznych naley wybiera funkcj
jak najniszego poziomu. Na przykad do obsugi plikw lepiej uy "bliskich
systemowi" funkcji zdefiniowanych w pliku io.h ni funkcji zdefiniowanych
w stdio.h.
Przy prbie doczania niektrych funkcji z bibliotek standardowych konsolidator moe zgosi komunikat o braku definicji pewnych symboli. Prawdopodobnie bd to zmienne definiowane w oryginalnym Startup-ie. Mona w takim
przypadku sprbowa zdefiniowania zmiennych o takich nazwach w programie
gwnym i zobaczy, czy program bdzie dziaa poprawnie (zwykle bdzie).
Wspominaem ju wczeniej, e wyjcie na ekran najlepiej realizowa
w programach rezydentnych przez bezporednie odwoania do pamici video.
Pami ekranu mona reprezentowa na wiele sposobw.
W poniszym programie zmienna screen jest zadeklarowana nastpujco:
char far *screen;
V. Kod wynikowy
103
/* rozmiar TSR-a w
/* potrzebne w
Sapek
Screen Saver (C) 92$";
*timer_ticks=MK_FP(0x0040,0x006c),
*screen,
*screen2;
struct {
unsigned char x,y;
}snake[4]={{4,4},{3,3},{2,2},{1,1}};
char dx[8]={0,1,2,1,0,-1,-2,-1},
dy[8]={-1,-1,0,1,1,1,0,-1};
unsigned off,time=300;
void at(char x,char y)
/* ustaw
wsprzdne (x,y) */
{
off=160*y+2*x;
}
void print(char *s)
/* pisz na ekranie cig
dwch znakw */
{
screen[off]=s[0];
screen[off+2]=s[1];
}
void move(unsigned char far* e1,unsigned char far *e2)
/*
przepisz e2 do e1 */
{
int x;
for(x=0;x<4000;x++)
e1[x]=e2[x],e2[x]=(x%2)?7:32;
}
void main()
{
char direct=3,y,x,a;
if(checkch()!=-1||time==300)
/* pocztek lub
nacinito klawisz */
{ time=timer_ticks[1]; srand(*timer_ticks); } /* zapamitaj
czas posiej
*/
/* generator
liczb losowych */
if((unsigned char)(timer_ticks[1]-time)>=13)
/* czy miny
3 min. ?
*/
{
104
Wgb jzyka C
if(*(char far *)0x449==7)
pami video ?
*/
screen=MK_FP(0xb000,0x0000);
B000:0
*/
else
screen=MK_FP(0xb800,0x0000);
B000:0
*/
screen2=screen+4000;
druga strona
*/
/* gdzie
/* Hercules ->
move(screen2,screen);
zawarto ekranu */
/* przepisz
hide_cursor();
kursor
*/
/* schowaj
while(checkch()==-1)
zosatnie nacinity*/
{
klawisz
*/
do{ if(rand()%11==0)direct=rand()%8;
11 krokw nowy */
x=snake[0].x+dx[direct];
*/
y=snake[0].y+dy[direct];
}while(x<0||x>=79||y<0||y>24);
tym kierunku */
/* a nie
wa
at(x,y);
print("");
*/
at(snake[0].x,snake[0].y);
at(snake[1].x,snake[1].y);
at(snake[2].x,snake[2].y);
at(snake[3].x,snake[3].y);
print("");
print("");
print("");
print(" ");
for(a=3;a>=1;a--)
/* jakis
/* rednio co
/* kierunek
/* czy mona w
/* rysuj
/* przesu wa
*/
{
snake[a].x=snake[a-1].x;
snake[a].y=snake[a-1].y;
}
snake[0].x=x; snake[0].y=y;
time=*timer_ticks;
while(*timer_ticks-time<4);
/* poczekaj 4
takty zagara
*/
}
_getch();
/* pobierz znak z bufora
*/
move(screen,screen2);
/* odtwrz ekran
*/
time=timer_ticks[1];
show_cursor();
/* poka kursor
*/
}
}
W celu uzyskania programu SAVER.COM, instalowanego jako program rezydentny przechwytujcy przerwanie 16h, naley skompilowa plik SAVER.C
w modelu Small, po czym poczy otrzymany plik SAVER.OBJ z odpowiednim
kodem startowym i bibliotecznymi:
tsr 16 saver getch checkch kursor
'?3,.21?GRF