YAzyk programmirovaniya Si.
Proizvodstvenno-vnedrencheskij kooperativ
"I N T E R F E J S"
Dialogovaya Edinaya Mobil'naya
Operacionnaya Sistema
Demos/P 2.1
YAzyk programmirovaniya Si.
Moskva
1988
Opisan universal'nyj yazyk programmirovaniya Si. Prive-
deny struktura i sintaksis yazyka, pravila napisaniya prog-
ramm, dany nachal'nye svedeniya o vzaimodejstvii programm na
Si s operacionnoj sistemoj Demos.
YAzyk Si - eto universal'nyj yazyk programmirovaniya, dlya
kotorogo harakterny ekonomichnost' vyrazheniya, sovremennyj
nabor operatorov i tipov dannyh. YAzyk Si ne yavlyaetsya ni
yazykom "ochen' vysokogo urovnya", ni "bol'shim" yazykom, i ne
prednaznachaetsya dlya nekotoroj special'noj oblasti primene-
niya, no otsutstvie ogranichenij i obshchnost' yazyka delayut ego
dlya mnogih zadach bolee udobnym i effektivnym, chem yazyki,
predpolozhitel'no bolee moshchnye. Operacionnaya sistema, kompi-
lyator s yazyka Si i po sushchestvu vse prikladnye programmy sis-
temy "DEMOS" napisany na Si. YAzyk Si ne svyazan s kakimi-
libo opredelennymi apparatnymi sredstvami ili sistemami, i
na nem legko pisat' programmy, kotorye mozhno propuskat' bez
izmenenij na lyuboj |VM, imeyushchej Si-kompilyator.
YAzyk Si yavlyaetsya universal'nym yazykom programmirovaniya.
On pervonachal'no poyavilsya v operacionnoj sisteme UNIX, i
razvivalsya kak osnovnoj yazyk sistem, sovmestimyh s OS UNIX.
Sam yazyk , odnako, ne svyazan s kakoj-libo odnoj operacionnoj
sistemoj ili mashinoj; i hotya ego nazyvayut yazykom sistemnogo
programmirovaniya, tak kak on udoben dlya napisaniya operacion-
nyh sistem, on mozhet ispol'zovat'sya dlya napisaniya lyubyh
bol'shih vychislitel'nyh programm, programm dlya obrabotki
tekstov i baz dannyh.
YAzyk Si - eto yazyk otnositel'no "nizkogo urovnya". |to
oznachaet, chto Si imeet delo s ob容ktami togo zhe vida, chto i
bol'shinstvo |VM, a imenno, s simvolami, chislami i adresami.
Oni mogut ob容dinyat'sya i peresylat'sya posredstvom obychnyh
arifmeticheskih i logicheskih operacij, osushchestvlyaemyh real'-
nymi |VM.
V yazyke Si otsutstvuyut operacii, imeyushchie delo nepos-
redstvenno s sostavnymi ob容ktami, takimi kak stroki simvo-
lov, mnozhestva, spiski ili s massivami, rassmatrivaemymi kak
celoe. Zdes', naprimer, net nikakogo analoga operaciyam PL/1,
operiruyushchim s massivami i strokami. YAzyk ne predostavlyaet
nikakih drugih vozmozhnostej raspredeleniya pamyati, krome sta-
ticheskogo opredeleniya i mehanizma stekov, obespechivaemogo
lokal'nymi peremennyh funkcij. Sam po sebe yazyk Si ne obes-
pechivaet nikakih vozmozhnostej vvoda-vyvoda. Vse eti meha-
nizmy vysokogo urovnya dolzhny obespechivat'sya yavno vyzyvaemymi
funkciyami.
Analogichno, yazyk Si predlagaet tol'ko prostye, posledo-
vatel'nye konstrukcii upravleniya: proverki, cikly, gruppiro-
vanie i podprogrammy, no ne mul'tiprogrammirovanie, paral-
lel'nye operacii, sinhronizaciyu ili soprogrammy.
Uderzhanie yazyka v skromnyh razmerah daet real'nye prei-
mushchestva. Tak kak Si otnositel'no mal, on ne trebuet mnogo
mesta dlya svoego opisaniya i mozhet byt' bystro vyuchen.
-1-
Kompilyator s Si mozhet byt' prostym i kompaktnym. |to obes-
pechivaet vysokuyu stepen' mobil'nosti yazyka. Poskol'ku tipy
dannyh i struktury upravleniya, imeyushchiesya v Si, neposredst-
venno podderzhivayutsya bol'shinstvom sushchestvuyushchih |VM, biblio-
teka, neobhodimaya vo vremya progona izolirovannyh programm,
okazyvaetsya ochen' malen'koj. Na SM-4, naprimer , ona soder-
zhit tol'ko programmy dlya 32-bitovogo umnozheniya i deleniya i
dlya upryatyvaniya i vosstanovleniya registrov pri vhode v funk-
ciyu. Konechno, kazhdaya realizaciya obespechivaet ischerpyvayushchuyu,
sovmestimuyu biblioteku funkcij dlya vypolneniya operacij
vvoda-vyvoda, obrabotki strok i raspredeleniya pamyati, no tak
kak obrashchenie k nim osushchestvlyaetsya tol'ko yavno, mozhno, esli
neobhodimo, izbezhat' ih vyzova; eti funkcii mogut byt' kom-
paktno napisany na samom Si.
Opyat' zhe iz-za togo, chto yazyk Si otrazhaet vozmozhnosti
sovremennyh komp'yuterov, programmy na Si okazyvayutsya dosta-
tochno effektivnymi, tak chto ne voznikaet pobuzhdeniya pisat'
vmesto etogo programmy na yazyke assemblera. Hotya Si soot-
vetstvuet vozmozhnostyam mnogih |VM, on ne zavisit ot kakoj-
libo konkretnoj arhitektury mashiny i v silu etogo bez osobyh
usilij pozvolyaet pisat' "perenosimye" programmy, t.e. prog-
rammy, kotorye mozhno propuskat' bez izmenenij na razlichnyh
apparatnyh sredstvah.
YAzyk Si ne yavlyaetsya yazykom so strogimi tipami dannyh v
smysle Paskalya ili Algola-68. On sravnitel'no snishoditelen
k preobrazovaniyu dannyh, hotya i ne budet bujno preobrazovy-
vat' tipy dannyh podobno yazyku PL/1. Kompilyator ne predus-
matrivaet nikakoj proverki indeksov massivov, tipov argumen-
tov i t.d. vo vremya vypolneniya programmy.
V teh situaciyah, kogda zhelatel'na strogaya proverka
tipov, ispol'zuetsya special'naya programma lint. Programma
lint ne generiruet mashinnogo koda, a delaet ochen' stroguyu
proverku vseh teh storon programmy, kotorye mozhno prokontro-
lirovat' vo vremya kompilyacii i zagruzki. Ona opredelyaet
nesootvetstvie tipov, nesovmestimost' argumentov, neispol'-
zovannye ili ochevidnym obrazom neinicializirovannye peremen-
nye, potencial'nye trudnosti perenosimosti i t.d.
Iz za togo, chto v yazyke otsutstvuyut sredstva
vvoda/vyvoda i t.p., pri programmirovanii na nem sushchestven-
nuyu rol' igraet biblioteka standartnyh programm, osushchestvlya-
yushchih vzaimodejstvie s sistemoj. Vo vseh sistemah, sovmesti-
myh s OS UNIX, k kotorym otnositsya i DEMOS, sushchestvuet sov-
mestimyj nabor programm dlya vvoda/vyvoda, upravleniya
pamyat'yu, preobrazovaniya dannyh i vypolnyayushchih drugie funkcii,
ispol'zovanie kotoryh obespechivaet vozmozhnost' perenosa
programm na drugie |VM.
V dannom dokumente opisyvaetsya yazyk Si, rasshireniya,
obespechivaemye special'nym preprocessorom (fakticheski oni
-2-
voshli uzhe v ponyatie "yazyk Si"), standartnaya biblioteka
vvoda/vyvoda, i dayutsya nachal'nye svedeniya o vzaimodejstvii
programm na Si s OS DEMOS. Polnoe opisanie bibliotechnyh
programm imeetsya v rukovodstve programmista OS DEMOS (chasti
3 i 4), i v operativnoj dokumentacii man(2) i man(3). Horo-
shim uchebnikom po yazyku Si yavlyaetsya kniga [1], kratkoe for-
mal'noe opisanie yazyka privedeno v [2].
V tekste vstrechayutsya primechaniya, otnosyashchiesya k realiza-
cii yazyka Si v OS DEMOS. Takie primechaniya vydelyayutsya verti-
kal'noj chertoj sprava (kak vydelen dannyj abzac).
* 2. SINTAKSICHESKAYA NOTACIYA
V ispol'zuemoj v etom rukovodstve sintaksicheskoj nota-
cii sintaksicheskie kategorii zapisyvayutsya russkimi bukvami i
simvolom "_", a vse ostal'nye simvoly rassmatrivayutsya kak
liternye (to est' izobrazhayushchie sami sebya). Al'ternativnye
kategorii perechislyayutsya na otdel'nyh strochkah. Neobyazatel'-
nyj simvol, terminal'nyj ili neterminal'nyj, ukazyvaetsya
indeksom "neob", tak chto
{ vyrazhenie }
neob
ukazyvaet na neobyazatel'noe vyrazhenie, zaklyuchennoe v figur-
nyh skobkah. Sintaksis opisyvaetsya v Prilozhenii 1.
Esli opisanie ne pomeshchaetsya na odnoj stroke, ono pro-
dolzhaetsya na sleduyushchej s nekotorym sdvigom vpravo, naprimer:
opisanie_struktury:
specifikator_tipa
spisok_opisatelej_struktury
Zdes' sleduet chitat':
opisanie_struktury:
specifikator_tipa spisok_opisatelej_struktury
Esli sdelan razbor vhodnogo potoka na leksemy vplot' do
dannogo simvola, to v kachestve sleduyushchej leksemy beretsya
samaya dlinnaya stroka simvolov,
IBM/370 (OS-360) 7 simvolov, 1 registr
VAX 11 (UNIX) 7 simvolov, 2 registra
Sleduyushchie identifikatory zarezervirovany dlya ispol'zo-
vaniya v kachestve klyuchevyh slov i ne mogut ispol'zovat'sya
inym obrazom:
-3-
int extern else
char register for
float typedef do
double static while
struct goto switch
union return case
long sizeof default
short break entry
unsigned continue
auto if
Klyuchevoe slovo entry v nastoyashchee vremya ne ispol'zuetsya
kakim-libo kompilyatorom; ono zarezervirovano dlya ispol'zova-
niya v budushchem. V nekotoryh realizaciyah rezerviruyutsya takzhe
slova fortran i asm.
Imeetsya neskol'ko vidov konstant, kotorye perechisleny
nizhe.
Celaya konstanta, sostoyashchaya iz posledovatel'nosti cifr,
schitaetsya vos'merichnoj, esli ona nachinaetsya s 0 (cifra
nul'), i desyatichnoj v protivnom sluchae. Cifry 8 i 9 imeyut
vos'merichnye znacheniya 10 i 11 sootvetstvenno. Posledova-
tel'nost' cifr, kotoroj predshestvuyut simvoly 0h (nul', h-
malen'koe) ili 0h (nul' X-bol'shoe), rassmatrivaetsya kak
shestnadcatirichnoe celoe. SHestnadcatirichnye cifry vklyuchayut
bukvy ot a (malen'koe) ili A (bol'shoe) do f (malen'koe) ili
F (bol'shoe) so znacheniyami ot 10 do 15. Desyatichnaya konstanta,
velichina kotoroj prevyshaet naibol'shee mashinnoe celoe so zna-
kom, schitaetsya dlinnoj; vos'merichnaya ili shestnadcatirichnaya
konstanta, kotoraya prevyshaet naibol'shee mashinnoe celoe bez
znaka, takzhe schitaetsya dlinnoj.
2.2.2. Dlinnye (long) konstanty
Desyatichnaya, vos'merichnaya ili shestnadcatirichnaya kons-
tanta, za kotoroj neposredstvenno sleduet l (el'-malen'koe)
ili L (el'-bol'shoe), yavlyaetsya dlinnoj konstantoj. Na nekoto-
ryh mashinah celye i dlinnye znacheniya mogut rassmatrivat'sya
kak identichnye.
2.2.3. Simvol'nye konstanty
Simvol'naya konstanta - eto simvol, zaklyuchennyj v odi-
nochnye kavychki, kak, naprimer, 'h'. Znacheniem simvol'noj
konstanty yavlyaetsya chislennoe znachenie etogo simvola v mashin-
nom predstavlenii nabora simvolov.
-4-
Nekotorye negraficheskie simvoly, odinochnaya kavychka ' i
obratnaya kosaya cherta \ mogut byt' predstavleny dvumya simvo-
lami v sootvetstvii so sleduyushchej tablicej uslovnyh posledo-
vatel'nostej:
Nazvanie Kod Oboznachenie
novaya stroka 012 \n
gorizontal'naya tabulyaciya 011 \t
simvol vozvrata na odnu 010 \v
poziciyu
vozvrat karetki 015 \r
perehod na novuyu stranicu 014 \f
obratnaya kosaya cherta 0133 \\
odinochnaya kavychka 047 \'
proizvol'nyj simvol 0ddd \ddd
Uslovnaya posledovatel'nost' \ddd sostoit iz obratnoj
kosoj cherty, za kotoroj sleduyut 1, 2 ili 3 vos'merichnyh
cifry, kotorye rassmatrivayutsya kak zadayushchie znachenie zhelae-
mogo simvola. Special'nym sluchaem etoj konstrukcii yavlyaetsya
posledovatel'nost' \0 (za nulem ne sleduet cifra), kotoraya
opredelyaet nulevoj simvol. Esli sleduyushchij za obratnoj kosoj
chertoj simvol ne sovpadaet s odnim iz ukazannyh, to obratnaya
kosaya cherta ignoriruetsya.
2.2.4. Veshchestvennye konstanty
Veshchestvennaya konstanta sostoit iz celoj chasti, desyatich-
noj tochki, drobnoj chasti, bukvy e (malen'kaya) ili E (bol'-
shaya) i celoj eksponenty s neobyazatel'nym znakom. Kak celaya,
tak i drobnaya chast' yavlyayutsya posledovatel'nost'yu cifr. Libo
celaya, libo drobnaya chast' (no ne obe) mozhet otsutstvovat';
libo desyatichnaya tochka, libo e i eksponenta (no ne to i dru-
goe odnovremenno) mozhet otsutstvovat'. Veshchestvennye kons-
tanty v bol'shinstve realizacij schitayutsya konstantami dvojnoj
tochnosti.
Stroka - eto posledovatel'nost' simvolov, zaklyuchennaya v
dvojnye kavychki, kak, naprimer, "...". Stroka imeet tip mas-
siv simvolov i klass pamyati static (sm. nizhe). Stroka inici-
alizirovana ukazannymi v nej simvolami. Vse stroki, dazhe
identichno zapisannye, schitayutsya razlichnymi. Kompilyator
pomeshchaet v konec kazhdoj stroki nulevoj bajt \0, s tem chtoby
prosmatrivayushchaya stroku programma mogla opredelit' ee konec.
Pered stoyashchim vnutri stroki simvolom dvojnoj kavychki " dol-
zhen byt' postavlen simvol obratnoj kosoj cherty \; krome
togo, mogut ispol'zovat'sya te zhe uslovnye posledovatel'-
nosti, chto i v simvol'nyh konstantah. Obratnaya kosaya cherta
\, za kotoroj neposredstvenno sleduet simvol novoj stroki,
-5-
ignoriruetsya.
Imeyutsya makroprocessornye sredstva, pozvolyayushchie ob容di-
nyat' sovpadayushchie stroki pri translyacii s cel'yu ekonomii
pamyati (sm. komandu xstr).
2.4. Harakteristiki apparatnyh sredstv
Sleduyushchaya nizhe tablica summiruet nekotorye svojstva
apparatnogo oborudovaniya, kotorye menyayutsya ot mashiny k
mashine. Hotya oni i vliyayut na perenosimost' programm, na
praktike oni predstavlyayut men'shuyu problemu, chem eto mozhet
kazat'sya zaranee.
Tablica 1.
-----------------------------------------
| CM-|VM IBM 370 (OS) VAX-11 |
| KOI-8 ebcdic ASCII |
| char 8 bit 8 bit 8 bit |
| int 16 32 32 |
| short 16 16 16 |
| long 32 32 32 |
| float 32 32 32 |
| double 64 64 64 |
| range -38/+38 -76/+76 -76/+76 |
|_______________________________________|
3.1. Interpretaciya identifikatorov
S kazhdym identifikatorom v Si svyazano dva atributa: ego
klass pamyati i ego tip. Klass pamyati opredelyaet mesto i
vremya hraneniya pamyati, svyazannoj s identifikatorom; tip
opredelyaet smysl velichin, nahodyashchihsya v pamyati, opredelennoj
pod identifikatorom.
Imeyutsya chetyre klassa pamyati: avtomaticheskaya, statiches-
kaya, vneshnyaya i registrovaya. Avtomaticheskie peremennye yavlya-
yutsya lokal'nymi dlya kazhdogo vyzova bloka i ischezayut pri
vyhode iz etogo bloka. Staticheskie peremennye yavlyayutsya
lokal'nymi, no sohranyayut svoi znacheniya dazhe posle togo, kak
upravlenie peredaetsya za predely bloka. Vneshnie peremennye
sushchestvuyut i sohranyayut svoi znacheniya v techenie vypolneniya
vsej programmy i mogut ispol'zovat'sya dlya svyazi mezhdu funk-
ciyami, v tom chisle i mezhdu nezavisimo skompilirovannymi
funkciyami. Registrovye peremennye hranyatsya (esli eto voz-
mozhno) v bystryh registrah mashiny; podobno avtomaticheskim
peremennym oni yavlyayutsya lokal'nymi dlya kazhdogo bloka i ische-
zayut pri vyhode iz etogo bloka.
V yazyke Si predusmotreno neskol'ko osnovnyh tipov
ob容ktov:
-6-
Simvol'nyj.
- Ob容kty, opisannye kak simvoly (char), dostatochno
veliki, chtoby hranit' lyuboj chlen iz sootvetstvuyushchego
dannoj realizacii vnutrennego nabora simvolov, i esli
dejstvitel'nyj simvol iz etogo nabora simvolov hra-
nitsya v simvol'noj peremennoj, to ee znachenie ekviva-
lentno celomu kodu etogo simvola. V simvol'nyh pere-
mennyh mozhno hranit' i drugie velichiny, no realizaciya
budet mashinno-zavisimoj. (Na SM |VM znachenie simvol'-
nyh peremennyh izmenyaetsya ot -0177 do 0177.)
Celyj.
- Mozhno ispol'zovat' do treh razmerov celyh, opisyvae-
myh kak short int, int i long int. Dlinnye celye
zanimayut ne men'she pamyati, chem korotkie, no v konk-
retnoj realizacii mozhet okazat'sya, chto libo korotkie
celye, libo dlinnye celye, libo te i drugie budut
ekvivalentny prostym celym. "Prostye" celye imeyut
estestvennyj razmer, predusmatrivaemyj arhitekturoj
ispol'zuemoj mashiny; drugie razmery vvodyatsya dlya
udovletvoreniya special'nyh potrebnostej.
Bezznakovyj.
- Celye bez znaka, opisyvaemye kak unsigned, podchinya-
yutsya zakonam arifmetiki po modulyu 2**n, gde n - chislo
bitov v ih predstavlenii. (Na CM-|VM dlinnye veli-
chiny bez znaka ne predusmotreny).
Veshchestvennyj.
- Veshchestvennye odinarnoj tochnosti (float) i veshchestven-
nye dvojnoj tochnosti (double) v nekotoryh realizaciyah
mogut byt' sinonimami. (Na SM |VM float zanimaet 32
bita pamyati, a double - 64).
V yazyke net logicheskogo tipa dannyh, a v kachestve logicheskih
znachenij ispol'zuyutsya celye "0" - "lozh'" i "1" - "istina"
(pri proverkah lyuboe celoe, ne ravnoe 0, traktuetsya kak
"istina").
Poskol'ku ob容kty upomyanutyh vyshe tipov mogut byt'
razumno interpretirovany kak chisla, eti tipy budut nazy-
vat'sya arifmeticheskimi. Tipy char i int vseh razmerov sov-
mestno budut nazyvat'sya celochislennymi. Tipy float i double
sovmestno budut nazyvat'sya veshchestvennymi tipami.
Krome osnovnyh arifmeticheskih tipov sushchestvuet koncep-
tual'no beskonechnyj klass proizvodnyh tipov, kotorye obrazu-
yutsya iz osnovnyh tipov sleduyushchim obrazom:
- massivy ob容ktov bol'shinstva tipov;
- funkcii, kotorye vozvrashchayut ob容kty zadannogo tipa;
-7-
- ukazateli na ob容kty dannogo tipa;
- struktury, soderzhashchie posledovatel'nost' ob容ktov
razlichnyh tipov;
- ob容dineniya, sposobnye soderzhat' odin iz neskol'kih
ob容ktov razlichnyh tipov.
Voobshche govorya, eti metody postroeniya ob容ktov mogut
primenyat'sya rekursivno.
3.2. Ob容kty i l_znacheniya
Ob容kt yavlyaetsya dostupnym obrabotke uchastkom pamyati;
l_znachenie (levoe znachenie) - eto vyrazhenie, ssylayushcheesya na
ob容kt. Ochevidnym primerom vyrazheniya l_znacheniya yavlyaetsya
identifikator. Sushchestvuyut operacii, rezul'tatom kotoryh
yavlyayutsya l_znacheniya; esli, naprimer, e - vyrazhenie tipa uka-
zatel', to *e yavlyaetsya vyrazheniem l_znacheniya, ssylayushchimsya na
tot ob容kt, na kotoryj ukazyvaet e. Nazvanie "l_znachenie"
proishodit ot vyrazheniya prisvaivaniya e1=e2, v kotorom levaya
chast' dolzhna byt' vyrazheniem l_znacheniya. Pri posleduyushchem
obsuzhdenii kazhdoj operacii budet ukazyvat'sya, ozhidaet li ona
operandov l_znacheniya i vydaet li ona l_znachenie.
Ryad operacij mozhet v zavisimosti ot svoih operandov
vyzyvat' preobrazovanie znacheniya operanda iz odnogo tipa v
drugoj. V etom razdele ob座asnyayutsya rezul'taty, kotorye sle-
duet ozhidat' ot takih preobrazovanij. V konce podvodyatsya
itogi preobrazovanij, trebuemye bol'shinstvom obychnyh opera-
cij; eti svedeniya dopolnyayutsya neobhodimym obrazom pri obsuzh-
denii kazhdoj operacii.
Simvol ili korotkoe celoe mozhno ispol'zovat' vsyudu, gde
mozhno ispol'zovat' celoe. Vo vseh sluchayah znachenie preobra-
zuetsya k celomu. Preobrazovanie bolee korotkogo celogo k
bolee dlinnomu vsegda soprovozhdaetsya znakovym rasshireniem;
celye yavlyayutsya velichinami so znakom. Osushchestvlyaetsya ili net
znakovoe rasshirenie dlya simvolov, zavisit ot ispol'zuemoj
mashiny, na SM-|VM takoe preobrazovanie osushchestvlyaetsya tak,
chto russkie bukvy pri pryamom preobrazovanii poluchat otrica-
tel'nye kody. Oblast' znachenij simvol'nyh peremennyh na
CM-|VM menyaetsya ot -128 do 127; simvoly iz nabora ASCII
imeyut polozhitel'nye znacheniya. Simvol'naya konstanta, zadan-
naya s pomoshch'yu vos'merichnoj uslovnoj posledovatel'nosti, pod-
vergaetsya znakovomu rasshireniyu i mozhet okazat'sya otricatel'-
noj; naprimer, '\377' imeet znachenie -1.
-8-
Kogda bolee dlinnoe celoe preobrazuetsya v bolee korot-
koe ili v char, ono obrezaetsya sleva; lishnie bity prosto
otbrasyvayutsya.
3.3.2. Tipy float i double
Vsya veshchestvennaya arifmetika v Si vypolnyaetsya s dvojnoj
tochnost'yu. Kazhdyj raz, kogda ob容kt tipa float poyavlyaetsya v
vyrazhenii, on udlinyaetsya do double posredstvom dobavleniya
nulej v ego drobnuyu chast'. Kogda ob容kt tipa double dolzhen
byt' preobrazovan k tipu float, naprimer, pri prisvaivanii,
pered usecheniem double okruglyaetsya do dliny float.
Edinstvennoe isklyuchenie mozhet byt' sdelano v kompilyato-
rah dlya |VM, na kotoryh net apparatnyh operacij nad chislami
tipa double (naprimer, SM-4). Utochnit' eto mozhno po opisa-
niyu kompilyatora (komanda cc).
3.3.3. Veshchestvennye i celochislennye velichiny
Preobrazovanie veshchestvennyh znachenij k celochislennomu
tipu v nekotoroj stepeni mashinno-zavisimo; v chastnosti, nap-
ravlenie usecheniya otricatel'nyh chisel menyaetsya ot mashine k
mashine. Rezul'tat ne opredelen, esli znachenie ne pomeshchaetsya
v predostavlyaemoe prostranstvo.
Preobrazovanie celochislennyh znachenij v veshchestvennye
vypolnyaetsya bez oslozhnenij. Mozhet proizojti nekotoraya poterya
tochnosti, esli dlya rezul'tata ne hvatit dliny mantissy.
Celoe ili dlinnoe celoe mozhet byt' pribavleno k ukaza-
telyu ili vychteno iz nego; v etom sluchae pervaya velichina pre-
obrazuetsya tak, kak ukazyvaetsya v opisanii operacii slozhe-
niya.
Dva ukazatelya na ob容kty odinakovogo tipa mogut byt'
vychteny; v etom sluchae rezul'tat preobrazuetsya k celomu, kak
ukazyvaetsya v opisanii operacii vychitaniya.
Vsyakij raz, kogda celoe bez znaka ob容dinyaetsya s pros-
tym celym, prostoe celoe preobrazuetsya v celoe bez znaka i
rezul'tat okazyvaetsya celym bez znaka. Znacheniem yavlyaetsya
naimen'shee celoe bez znaka, sootvetstvuyushchee celomu so znakom
(po modulyu 2**razmer slova). V dvoichnom dopolnitel'nom
predstavlenii eto preobrazovanie yavlyaetsya chisto umozritel'-
nym i ne izmenyaet fakticheskuyu kombinaciyu bitov.
Kogda celoe bez znaka preobrazuetsya k tipu long, znache-
nie rezul'tata sovpadaet so znacheniem celogo bez znaka.
-9-
Takim obrazom, eto preobrazovanie svoditsya k dobavleniyu
nulej sleva.
3.3.6. Arifmeticheskie preobrazovaniya
Podavlyayushchee bol'shinstvo operacij vyzyvaet preobrazova-
nie i opredelyaet tipy rezul'tata analogichnym obrazom. Privo-
dimaya nizhe shema v dal'nejshem budet nazyvat'sya "obychnymi
arifmeticheskimi preobrazovaniyami". Snachala lyubye operandy
tipa char ili short preobrazuyutsya v int, a lyubye operandy
tipa float preobrazuyutsya v double. Zatem, esli kakoj-libo
operand imeet tip double, to drugoj preobrazuetsya k tipu
double, i eto budet tipom rezul'tata. V protivnom sluchae,
esli kakoj-libo operand imeet tip long, to drugoj operand
preobrazuetsya k tipu long, i eto i budet tipom rezul'tata.
V protivnom sluchae, esli kakoj-libo operand imeet tip
unsigned, to drugoj operand preobrazuetsya k tipu unsigned, i
eto budet tipom rezul'tata. V protivnom sluchae oba operanda
budut imet' tip int, i eto budet tipom rezul'tata.
Starshinstvo operacij v vyrazheniyah sovpadaet s poryadkom
sledovaniya osnovnyh podrazdelov nastoyashchego razdela, nachinaya
s samogo vysokogo urovnya starshinstva. Tak, naprimer, vyrazhe-
niyami, ukazyvaemymi v kachestve operandov operacii + (p.0.4),
yavlyayutsya vyrazheniya, opredelennye v p.p.0.1-0.3. Vnutri kazh-
dogo podrazdela operacii imeyut odinakovoe starshinstvo. V
kazhdom podrazdele dlya opisyvaemyh tam operacij ukazyvaetsya
ih associativnost' sleva ili sprava. Starshinstvo i associa-
tivnost' vseh operacij v vyrazheniyah rezyumiruyutsya v grammati-
cheskoj svodke v prilozhenii.
V protivnom sluchae poryadok vychislenij vyrazhenij ne
opredelen. V chastnosti, kompilyator mozhet vychislyat' podvyra-
zheniya v tom poryadke, kotoryj on nahodit naibolee effektiv-
nym, dazhe esli eti podvyrazheniya privodyat k pobochnym effek-
tam. Poryadok, v kotorom proishodyat pobochnye effekty, ne spe-
cificiruetsya. Vyrazheniya, vklyuchayushchie kommutativnye i associa-
tivnye operacii (*,+,&,|,^), mogut byt' pereuporyadocheny pro-
izvol'nym obrazom dazhe pri nalichii kruglyh skobok; v etom
sluchae neobhodimo ispol'zovat' yavnye promezhutochnye peremen-
nye.
Pri vychislenii vyrazhenij obrabotka perepolneniya i pro-
verka pri delenii yavlyayutsya mashinno-zavisimymi. Bol'shinstvo
realizacij yazyka Si (v tom chisle i v OS DEMOS) ignoriruyut
perepolnenie celyh; obrabotka oshibki pri delenii na 0 i pri
vseh osobyh sluchayah v operaciyah s veshchestvennymi chislami
menyaetsya ot mashiny k mashine i obychno vypolnyaetsya s pomoshch'yu
bibliotechnoj funkcii.
-10-
4.1. Pervichnye vyrazheniya
Pervichnye vyrazheniya, vklyuchayushchie ., ->, indeksaciyu i
obrashcheniya k funkciyam, gruppiruyutsya sleva napravo.
pervichnoe vyrazhenie:
identifikator
konstanta
stroka
(vyrazhenie)
pervichnoe_vyrazhenie [vyrazhenie]
pervichnoe_vyrazhenie (spisok_vyrazhenij)
neob
pervichnoe_l_znachenie . Identifikator
pervichnoe_vyrazhenie -> identifikator
spisok_vyrazhenij:
vyrazhenie
spisok_vyrazhenij, vyrazhenie
Identifikator yavlyaetsya pervichnym vyrazheniem pri uslovii, chto
on opisan podhodyashchim obrazom, kak eto obsuzhdaetsya nizhe. Tip
identifikatora opredelyaetsya ego opisaniem. Esli, odnako,
tipom identifikatora yavlyaetsya massiv ..., to znacheniem vyra-
zheniya, sostoyashchego iz etogo identifikatora, yavlyaetsya ukaza-
tel' na pervyj ob容kt v etom massive, a tipom vyrazheniya
budet ukazatel' na .... Bolee togo, identifikator massiva ne
yavlyaetsya vyrazheniem l_znacheniya. Podobnym obrazom interpreti-
ruetsya identifikator, kotoryj opisan kak funkciya, vozvrashchayu-
shchaya .... Za isklyucheniem togo sluchaya, kogda on ispol'zuetsya v
pozicii imeni funkcii pri obrashchenii, preobrazuetsya v ukaza-
tel' na funkciyu, kotoraya vozvrashchaet ....
Konstanta yavlyaetsya pervichnym vyrazheniem. V zavisimosti
ot ee formy tipom konstanty mozhet byt' int, long ili double.
Stroka yavlyaetsya pervichnym vyrazheniem. Ishodnym ee tipom
yavlyaetsya massiv simvolov; no sleduya tem zhe samym pravilam,
kotorye privedeny vyshe dlya identifikatorov, on modificiru-
etsya v ukazatel' na simvoly, i rezul'tatom yavlyaetsya ukaza-
tel' na pervyj simvol stroki. (Imeetsya isklyuchenie v nekoto-
ryh inicializatorah; sm. nizhe.)
Vyrazhenie v kruglyh skobkah yavlyaetsya pervichnym vyrazhe-
niem, tip i znachenie kotorogo identichny tipu i znacheniyu
etogo vyrazheniya bez skobok. Nalichie kruglyh skobok ne vli-
yaet na to, yavlyaetsya li vyrazhenie l_znacheniem ili net.
Pervichnoe vyrazhenie, za kotorym sleduet vyrazhenie v
kvadratnyh skobkah, yavlyaetsya pervichnym vyrazheniem. |to vyra-
zhenie s indeksom. Obychno pervichnoe vyrazhenie imeet tip uka-
zatel' na ..., indeksnoe vyrazhenie imeet tip int, a tipom
rezul'tata yavlyaetsya "...". Vyrazhenie e1[e2] po opredeleniyu
identichno vyrazheniyu * ((e1) + (e2)). Vse, chto neobhodimo
-11-
dlya ponimaniya etoj zapisi, soderzhitsya v etom razdele; vop-
rosy, svyazannye s ponyatiem identifikatorov i operacij * i +
rassmatrivayutsya v p.p. 0.1, 0.2 i 0.4 sootvetstvenno; vyvody
summiruyutsya nizhe.
Obrashchenie k funkcii yavlyaetsya pervichnym vyrazheniem, za
kotorym sleduet zaklyuchennyj v kruglye skobki vozmozhno pustoj
spisok vyrazhenij, razdelennyh zapyatymi, kotorye i predstav-
lyayut soboj fakticheskie argumenty funkcii. Pervichnoe vyrazhe-
nie dolzhno byt' tipa funkciya, vozvrashchayushchaya ..., a rezul'tat
obrashcheniya k funkcii imeet tip "...". Kak ukazyvaetsya nizhe,
ranee ne vstrechavshchijsya identifikator, za kotorym neposredst-
venno sleduet levaya kruglaya skobka, schitaetsya opisannym po
kontekstu, kak predstavlyayushchij funkciyu, vozvrashchayushchuyu celoe;
sledovatel'no chashche vsego vstrechayushchijsya sluchaj funkcii, vozv-
rashchayushchej celoe znachenie, ne nuzhdaetsya v opisanii.
Pered obrashcheniem lyubye fakticheskie argumenty tipa float
preobrazuyutsya k tipu double, lyubye argumenty tipa char ili
short preobrazuyutsya k tipu int, i, kak obychno, imena massi-
vov preobrazuyutsya v ukazateli. Nikakie drugie preobrazovaniya
ne vypolnyayutsya avtomaticheski; v chastnosti, ne sravnivayutsya
tipy fakticheskih argumentov s tipami formal'nyh argumentov.
Esli preobrazovanie neobhodimo, ispol'zujte yavnoe preobrazo-
vanie.
Pri podgotovke k vyzovu funkcii delaetsya kopiya kazhdogo
fakticheskogo parametra; takim obrazom, vse peredachi argumen-
tov v yazyke Si osushchestvlyayutsya strogo po znacheniyu. Funkciya
mozhet izmenyat' znacheniya svoih formal'nyh parametrov, no eti
izmeneniya ne vliyayut na znacheniya fakticheskih parametrov. S
drugoj storony, imeetsya vozmozhnost' peredavat' ukazatel',
pri etom funkciya mozhet izmenyat' znachenie ob容kta, na kotoryj
etot ukazatel' ukazyvaet. Poryadok vychisleniya argumentov v
yazyke ne opredelen; razlichnye kompilyatory vychislyayut po raz-
nomu.
Dopuskayutsya rekursivnye obrashcheniya k lyuboj funkcii.
Pervichnoe vyrazhenie, za kotorym sleduet tochka i identi-
fikator, yavlyaetsya vyrazheniem. Pervoe vyrazhenie dolzhno byt'
l_znacheniem, imenuyushchim strukturu ili ob容dinenie, a identi-
fikator dolzhen byt' imenem chlena struktury ili ob容dineniya.
Rezul'tatom yavlyaetsya l_znachenie, ssylayushcheesya na poimenovan-
nyj chlen struktury ili ob容dineniya.
Pervichnoe vyrazhenie, za kotorym sleduet strelka (sos-
tavlennaya iz znakov - i >) i identifikator, yavlyaetsya vyrazhe-
niem. Pervoe vyrazhenie dolzhno byt' ukazatelem na strukturu
ili ob容dinenie, a identifikator dolzhen imenovat' chlen etoj
struktury ili ob容dineniya. Rezul'tatom yavlyaetsya l_znachenie,
ssylayushcheesya na poimenovannyj chlen struktury ili ob容dineniya,
na kotoryj ukazyvaet ukazatel'noe vyrazhenie.
-12-
Sledovatel'no, vyrazhenie e1->mos yavlyaetsya tem zhe samym,
chto i vyrazhenie (*e1).mos. Struktury i ob容dineniya rassmat-
rivayutsya nizhe. Privedennye zdes' pravila ispol'zovaniya
struktur i ob容dinenij ne navyazyvayutsya strogo, dlya togo
chtoby imet' vozmozhnost' obojti mehanizm tipov (sm. "Dopol-
nitel'naya informaciya o tipah").
Vyrazhenie s unarnymi operaciyami gruppiruetsya sprava
nalevo.
unarnoe_vyrazhenie:
* vyrazhenie
& l_znachenie
- vyrazhenie
! vyrazhenie
~ vyrazhenie
++ l_znachenie
-- l_znachenie
l_znachenie ++
l_znachenie --
(imya-tipa) vyrazhenie
sizeof vyrazhenie
sizeof (imya_tipa)
Unarnaya operaciya * oznachaet kosvennuyu adresaciyu: vyrazhenie
dolzhno byt' ukazatelem, a rezul'tatom yavlyaetsya l_znachenie,
ssylayushcheesya na tot ob容kt, na kotoryj ukazyvaet vyrazhenie.
Esli tipom vyrazheniya yavlyaetsya ukazatel' na ..., to tipom
rezul'tata budet "...".
Rezul'tatom unarnoj operacii & yavlyaetsya ukazatel' na
ob容kt, k kotoromu ssylaetsya l_znachenie. Esli l_znachenie
imeet tip "...", to tipom rezul'tata budet ukazatel' na ....
Rezul'tatom unarnoj operacii - (minus) yavlyaetsya ee ope-
rand, vzyatyj s protivopolozhnym znakom. Dlya velichiny tipa
unsigned rezul'tat poluchaetsya vychitaniem ee znacheniya iz 2**n
(dva v stepeni n), gde n-chislo bitov v int. Unarnoj operacii
+ (plyus) ne sushchestvuet.
Rezul'tatom operacii logicheskogo otricaniya ! yavlyaetsya
1, esli znachenie ee operanda ravno 0, i 0, esli znachenie ee
operanda otlichno ot nulya. Rezul'tat imeet tip int. |ta ope-
raciya primenima k lyubomu arifmeticheskomu tipu ili ukazate-
lyam.
Operaciya ~ (simvol "til'da", nahoditsya na klavishe ^ v
nizhnem registre) daet obratnyj kod (ili dopolnenie do edi-
nicy) svoego operanda. Vypolnyayutsya obychnye arifmeticheskie
preobrazovaniya. Operand dolzhen byt' celochislennogo tipa.
-13-
Ob容kt, na kotoryj ssylaetsya operand l_znacheniya pre-
fiksnoj operacii ++, uvelichivaetsya. Znacheniem yavlyaetsya novoe
znachenie operanda, no eto ne l_znachenie. Vyrazhenie ++h ekvi-
valentno h += 1 . Informaciyu o preobrazovaniyah smotri v raz-
bore operacii slozheniya (p. 0.4) i operacii prisvaivaniya (p.
0.14).
Prefiksnaya operaciya -- analogichna prefiksnoj operacii
++, no privodit k umen'sheniyu svoego operanda l_znacheniya.
Pri primenenii postfiksnoj operacii ++ k l_znacheniyu
rezul'tatom yavlyaetsya znachenie ob容kta, na kotoryj ssylaetsya
l_znachenie. Posle togo, kak rezul'tat prinyat k svedeniyu,
ob容kt uvelichivaetsya tochno takim zhe obrazom, kak i v sluchae
prefiksnoj operacii ++. Rezul'tat imeet tot zhe tip, chto i
vyrazhenie l_znacheniya.
Pri primenenii postfiksnoj operacii -- k l_znacheniyu
rezul'tatom yavlyaetsya znachenie ob容kta, na kotoryj ssylaetsya
l_znachenie. Posle togo, kak rezul'tat prinyat k svedeniyu,
ob容kt umen'shaetsya tochno takim zhe obrazom, kak i v sluchae
prefiksnoj operacii --. Rezul'tat imeet tot zhe tip, chto i
vyrazhenie l_znacheniya.
Zaklyuchennoe v kruglye skobki imya tipa dannyh, stoyashchee
pered vyrazheniem, vyzyvaet preobrazovanie znacheniya etogo
vyrazheniya k ukazannomu tipu. |ta konstrukciya nazyvaetsya
perevod (cast). Imena tipov opisyvayutsya v sleduyushchem razdele.
Operaciya sizeof vydaet razmer svoego operanda v bajta.
(Ponyatie bajt v yazyke ne opredeleno, razve tol'ko, kak zna-
chenie operacii sizeof. Odnako vo vseh sushchestvuyushchih realiza-
ciyah bajtom yavlyaetsya prostranstvo, neobhodimoe dlya hraneniya
ob容kta tipa char). Pri primenenii k massivu rezul'tatom
yavlyaetsya polnoe chislo bajtov v massive. Razmer opredelyaetsya
iz opisanij ob容ktov v vyrazhenii. |to vyrazhenie semanticheski
yavlyaetsya celoj konstantoj i mozhet byt' ispol'zovano v lyubom
meste, gde trebuetsya konstanta. Osnovnoe primenenie eta ope-
raciya nahodit pri vyzove procedur, podobnyh raspredelitelyam
pamyati, i v sistemah vvoda- vyvoda.
Operaciya sizeof mozhet byt' takzhe primenena i k zaklyu-
chennomu v kruglye skobki imeni tipa. V etom sluchae ona
vydaet razmer v bajtah ob容kta ukazannogo tipa.
Konstrukciya sizeof (tip) rassmatrivaetsya kak celoe, tak
chto vyrazhenie sizeof (tip) - 2 ekvivalentno vyrazheniyu
(sizeof (tip)) - 2.
4.3. Mul'tiplikativnye operacii
Mul'tiplikativnye operacii *, /, i % gruppiruyutsya sleva
napravo. Vypolnyayutsya obychnye arifmeticheskie preobrazovaniya.
-14-
mul'tiplikativnoe_vyrazhenie:
vyrazhenie * vyrazhenie
vyrazhenie / vyrazhenie
vyrazhenie % vyrazhenie
Binarnaya operaciya * oznachaet umnozhenie. Operaciya *
associativna, i vyrazheniya s neskol'kimi umnozheniyami na odnom
i tom zhe urovne mogut byt' peregruppirovany kompilyatorom.
Binarnaya operaciya / oznachaet delenie. Pri delenii polo-
zhitel'nyh celyh osushchestvlyaetsya usechenie po napravleniyu k
nulyu, no esli odin iz operandov otricatelen, to forma useche-
niya zavisit ot ispol'zuemoj mashiny. Ostatok imeet tot zhe
znak, chto i delimoe. Vsegda spravedlivo, chto (a/b)*b+a%b
ravno a (esli b ne ravno 0).
Binarnaya operaciya % vydaet ostatok ot deleniya pervogo
vyrazheniya na vtoroe. Vypolnyayutsya obychnye arifmeticheskie pre-
obrazovaniya. Operandy dolzhny byt' celogo tipa.
Additivnye operacii + i - gruppiruyutsya sleva napravo.
Vypolnyayutsya obychnye arifmeticheskie preobrazovaniya. Dlya kazh-
doj operacii imeyutsya nekotorye dopolnitel'nye vozmozhnosti,
svyazannye s tipami operandov.
additivnoe_vyrazhenie:
vyrazhenie + vyrazhenie
vyrazhenie - vyrazhenie
Rezul'tatom operacii + yavlyaetsya summa operandov. Mozhno takzhe
skladyvat' ukazatel' na ob容kt v massive i znachenie lyubogo
celochislennogo tipa. Poslednee preobrazuetsya v adresnoe
smeshchenie posredstvom umnozheniya ego na dlinu ob容kta, na
kotoryj ukazyvaet etot ukazatel'. Rezul'tatom yavlyaetsya uka-
zatel' togo zhe samogo tipa, chto i ishodnyj ukazatel', koto-
ryj ukazyvaet na drugoj ob容kt v tom zhe massive, smeshchennyj
sootvetstvuyushchim obrazom otnositel'no pervonachal'nogo
ob容kta. Takim obrazom, esli p yavlyaetsya ukazatelem ob容kta v
massive, to vyrazhenie p+1 yavlyaetsya ukazatelem na sleduyushchij
ob容kt v etom massive.
Nikakie drugie kombinacii tipov dlya ukazatelej ne raz-
reshayutsya.
Operaciya + associativna, i vyrazhenie s neskol'kimi slo-
zheniyami na odnom i tom zhe urovne mogut byt' pereuporyadocheny
kompilyatorom.
-15-
Rezul'tatom operacii - yavlyaetsya raznost' operandov.
Vypolnyayutsya obychnye arifmeticheskie preobrazovaniya. Krome
togo, iz ukazatelya mozhet byt' vychteno znachenie lyubogo celo-
chislennogo tipa, prichem, provodyatsya te zhe samye preobrazova-
niya, chto i pri operacii slozheniya.
Esli vychitayutsya dva ukazatelya na ob容kty odinakovogo
tipa, to rezul'tat preobrazuetsya (deleniem na dlinu ob容kta)
k tipu int, predstavlyaya soboj chislo ob容ktov, razdelyayushchih
ukazyvaemye ob容kty. Esli eti ukazateli ne na ob容kty iz
odnogo i togo zhe massiva, to takoe preobrazovanie, voobshche
govorya, dast neozhidannye rezul'taty, potomu chto dazhe ukaza-
teli na ob容kty odinakovogo tipa ne obyazany otlichat'sya na
velichinu, kratnuyu dline ob容kta.
Operacii sdviga << i >> gruppiruyutsya sleva napravo.
Dlya obeih operacij provodyatsya obychnye arifmeticheskie preob-
razovaniya ih operandov, kazhdyj iz kotoryh dolzhen byt' celogo
tipa. Zatem pravyj operand preobrazuetsya k tipu int; rezul'-
tat imeet tip levogo operanda. Rezul'tat ne opredelen, esli
pravyj operand otricatelen ili bol'she ili raven, chem dlina
ob容kta v bitah.
vyrazhenie_sdviga:
vyrazhenie << vyrazhenie
vyrazhenie >> vyrazhenie
Znacheniem vyrazheniya e1<<e2 yavlyaetsya e1 (interpretiruemoe kak
kombinaciya bitov), sdvinutoe vlevo na e2 bitov; osvobozhdayu-
shchiesya bity zapolnyayutsya nulem. Znacheniem vyrazheniya e1>>e2
yavlyaetsya e1, sdvinutoe vpravo na e2 bitovyh pozicij. Esli e1
imeet tip unsigned, to sdvig vpravo garantirovanno budet
logicheskim (zapolnenie nulem); v protivnom sluchae sdvig
mozhet byt' (kak na CM-|VM) arifmeticheskim (osvobozhdayushchiesya
bity zapolnyayutsya kopiej znakovogo bita).
4.6. Operacii otnosheniya
Operacii otnosheniya gruppiruyutsya sleva napravo, no etot
fakt ne ochen' polezen; vyrazhenie a<b<c ne oznachaet togo, chto
ono ,kazalos' by, dolzhno oznachat', a oznachaet ((a<b)<c).
vyrazhenie_otnosheniya:
vyrazhenie < vyrazhenie
vyrazhenie > vyrazhenie
vyrazhenie <= vyrazhenie
vyrazhenie >= vyrazhenie
Operacii < (men'she), > (bol'she), <= (men'she ili ravno) i >=
(bol'she ili ravno) dayut 0, esli ukazannoe otnoshenie lozhno,
i 1, esli ono istinno. Rezul'tat imeet tip int. Vypolnyayutsya
-16-
obychnye arifmeticheskie preobrazovaniya. Mogut sravnivat'sya
dva ukazatelya; rezul'tat zavisit ot otnositel'nogo raspolo-
zheniya ukazyvaemyh ob容ktov v adresnom prostranstve. Sravne-
nie ukazatelej perenosimo tol'ko v tom sluchae, esli ukaza-
teli ukazyvayut na ob容kty iz odnogo i togo zhe massiva.
vyrazhenie_ravenstva:
vyrazhenie == vyrazhenie
vyrazhenie != vyrazhenie
Operacii == (ravno) i != (ne ravno) v tochnosti analogichny
operaciyam otnosheniya, za isklyucheniem togo, chto oni imeyut
bolee nizkij uroven' starshinstva. (poetomu znachenie vyrazhe-
niya a<b==c<d ravno 1 vsyakij raz, kogda vyrazheniya a<b i c<d
imeyut odinakovoe znachenie istinnosti).
Ukazatel' mozhno sravnivat' s celym, no rezul'tat budet
mashinno-nezavisimym tol'ko v tom sluchae, esli celym yavlyaetsya
konstanta 0. Garantiruetsya, chto ukazatel', kotoromu prisvo-
eno znachenie 0, ne ukazyvaet ni na kakoj ob容kt i na samom
dele okazyvaetsya ravnym 0; obshcheprinyato schitat' takoj ukaza-
tel' nulem.
4.8. Pobitovaya operaciya 'i'
vyrazhenie_i:
vyrazhenie & vyrazhenie
Operaciya & yavlyaetsya associativnoj, i vklyuchayushchie & vyrazheniya
mogut byt' pereuporyadocheny kompilyatorom. Vypolnyayutsya obych-
nye arifmeticheskie preobrazovaniya; rezul'tatom yavlyaetsya
pobitovaya funkciya 'i' operandov. |ta operaciya primenima
tol'ko k operandam celogo tipa.
4.9. Pobitovaya operaciya isklyuchayushchego 'ili'
vyrazhenie_isklyuchayushchego_ili:
vyrazhenie ^ vyrazhenie
Operaciya ^ (znak nadcherkivaniya, kod v KOI-8 0136) yavlyaetsya
associativnoj, i vklyuchayushchie ^ vyrazheniya mogut byt' pereupo-
ryadocheny kompilyatorom. Vypolnyayutsya obychnye arifmeticheskie
preobrazovaniya; rezul'tatom yavlyaetsya pobitovaya funkciya isk-
lyuchayushchego 'ili' operandov. Operaciya primenima tol'ko k ope-
randam celochislennogo tipa.
4.10. Pobitovaya operaciya vklyuchayushchego 'ili'
vyrazhenie_vklyuchayushchego_ili:
vyrazhenie | vyrazhenie
-17-
Operaciya | yavlyaetsya associativnoj, i soderzhashchie | vyrazheniya
mogut byt' pereuporyadocheny. Vypolnyayutsya obychnye arifmetiches-
kie preobrazovaniya; rezul'tatom yavlyaetsya pobitovaya funkciya
vklyuchayushchego 'ili' operandov. Operaciya primenima tol'ko k
operandam celochislennogo tipa.
4.11. Logicheskaya operaciya 'i'
vyrazhenie_logicheskogo_i:
vyrazhenie && vyrazhenie
Operaciya && gruppiruetsya sleva napravo. Ona vozvrashchaet 1,
esli oba ee operanda otlichny ot nulya, i 0 v protivnom slu-
chae. V otlichie ot & operaciya && garantiruet vychislenie sleva
napravo; bolee togo, esli pervyj operand raven 0, to znache-
nie vtorogo operanda voobshche ne vychislyaetsya.
Operandy ne obyazany byt' odinakovogo tipa, no kazhdyj iz
nih dolzhen byt' libo odnogo iz osnovnyh tipov, libo ukazate-
lem. Rezul'tat vsegda imeet tip int.
4.12. Operaciya logicheskogo 'ili'
vyrazhenie_logicheskogo_ili:
vyrazhenie || vyrazhenie
Operaciya || gruppiruetsya sleva napravo. Ona vozvrashchaet 1,
esli odin iz operandov otlichen ot nulya, i 0 v protivnom slu-
chae. V otlichie ot operacii | operaciya || garantiruet vychis-
lenie sleva napravo; bolee togo, esli pervyj operand otlichen
ot nulya, to znachenie vtorogo operanda voobshche ne vychislyaetsya.
Operandy ne obyazany byt' odinakovogo tipa, no kazhdyj iz
nih dolzhen byt' libo odnogo iz osnovnyh tipov, libo ukazate-
lem. Rezul'tat vsegda imeet tip int.
4.13. Uslovnaya operaciya
uslovnoe_vyrazhenie:
vyrazhenie ? vyrazhenie : vyrazhenie
Uslovnye vyrazheniya gruppiruyutsya sleva napravo. Vychislyaetsya
znachenie pervogo vyrazheniya, i esli ono otlichno ot nulya, to
rezul'tatom budet znachenie vtorogo vyrazheniya; v protivnom
sluchae rezul'tatom budet znachenie tret'ego vyrazheniya. Esli
eto vozmozhno, provodyatsya obychnye arifmeticheskie preobrazova-
niya, s tem, chtoby privesti vtoroe i tret'e vyrazheniya k
obshchemu tipu; v protivnom sluchae, esli oba vyrazheniya yavlyayutsya
ukazatelyami odinakovogo tipa, to rezul'tat imeet tot zhe tip;
v protivnom sluchae odno vyrazhenie dolzhno byt' ukazatelem, a
drugoe - konstantoj 0, i rezul'tat budet imet' tip ukaza-
telya. Vychislyaetsya tol'ko odno iz vtorogo i tret'ego vyrazhe-
nij.
-18-
4.14. Operaciya prisvaivaniya
Imeetsya ryad operacij prisvaivaniya, kazhdaya iz kotoryh
gruppiruetsya sleva napravo. Vse operacii trebuyut v kachestve
svoego levogo operanda l_znachenie, a tipom vyrazheniya prisva-
ivaniya yavlyaetsya tip ego levogo operanda. Znacheniem vyrazheniya
prisvaivaniya yavlyaetsya znachenie, hranimoe v levom operande
posle togo, kak prisvaivanie uzhe budet proizvedeno. Dve
chasti sostavnoj operacii prisvaivaniya yavlyayutsya otdel'nymi
leksemami.
vyrazhenie_prisvaivaniya:
l_znachenie = vyrazhenie
l_znachenie += vyrazhenie
l_znachenie -= vyrazhenie
l_znachenie *= vyrazhenie
l_znachenie /= vyrazhenie
l_znachenie %= vyrazhenie
l_znachenie >>= vyrazhenie
l_znachenie <<= vyrazhenie
l_znachenie &= vyrazhenie
l_znachenie ^= vyrazhenie
l_znachenie |= vyrazhenie
Kogda proizvoditsya prostoe prisvaivanie '=', znachenie
vyrazheniya zamenyaet znachenie ob容kta, na kotoroe ssylaetsya
l_znachenie. Esli oba operanda imeyut arifmeticheskij tip, to
pered prisvaivaniem pravyj operand preobrazuetsya k tipu
levogo operanda.
V vyrazhenie vida e1 op= e2, gde op - odna iz perechis-
lennyh vyshe operacij, ekvivalentno vyrazheniyu
e1 = e1 op (e2), s tem otlichiem, chto vyrazhenie e1 vychislya-
etsya tol'ko odin raz. V sluchae operacij += i -= levyj ope-
rand mozhet byt' ukazatelem, prichem pri etom (celochislennyj)
pravyj operand preobrazuetsya takim obrazom, kak ob座asneno v
p. 0.4; vse pravye operandy i vse otlichnye ot ukazatelej
levye operandy dolzhny imet' arifmeticheskij tip.
Ispol'zuemye v OS DEMOS kompilyatory dopuskayut prisvai-
vanie ukazatelya celomu, celogo ukazatelyu i ukazatelya ukaza-
telyu drugogo tipa. Takoe prisvaivanie yavlyaetsya chistym kopi-
rovaniem bez kakih-libo preobrazovanij. Takoe upotreblenie
operacij prisvaivaniya yavlyaetsya neperenosimym i mozhet privo-
dit' k ukazatelyam, kotorye pri ispol'zovanii vyzyvayut oshibki
adresacii. Tem ne menee garantiruetsya, chto prisvaivanie uka-
zatelyu konstanty 0 daet nulevoj ukazatel', kotoryj mozhno
otlichat' ot ukazatelya na lyuboj ob容kt.
-19-
4.15. Prisvaivanie struktury
Struktury mogut byt' prisvoeny, a takzhe peredany funk-
ciyam v kachestve argumentov i vozvrashcheny funkciyami. Tipy
uchastvuyushchih operandov dolzhny sovpadat'.
4.16. Operaciya 'zapyataya<
vyrazhenie_s_zapyatoj:
vyrazhenie , vyrazhenie
Para vyrazhenij, razdelennyh zapyatoj, vychislyaetsya sleva nap-
ravo i znachenie levogo vyrazheniya otbrasyvaetsya. Tipom i zna-
cheniem rezul'tata yavlyaetsya tip i znachenie pravogo operanda.
|ta operaciya gruppiruetsya sleva napravo. V kontekste, gde
zapyataya imeet special'noe znachenie, kak, naprimer, v spiske
fakticheskih argumentov funkcij ili v spiskah inicializato-
rov, operaciya zapyataya, opisyvaemaya v etom razdele, mozhet
poyavlyat'sya tol'ko v kruglyh skobkah; naprimer, funkciya
f(a,(t=3,t+2),c)
imeet tri argumenta, vtoroj iz kotoryh imeet znachenie 5.
4.17. Starshinstvo i poryadok vychisleniya.
V privodimoj nizhe tablice svedeny pravila starshinstva i
associativnosti vseh operacij. Operacii, raspolozhennye v
odnoj stroke, imeyut odin i tot zhe uroven' starshinstva;
stroki raspolozheny v poryadke ubyvaniya starshinstva. Tak, nap-
rimer, operacii *, "/" i "%" imeyut odinakovyj uroven' star-
shinstva, kotoryj vyshe, chem uroven' operacij "+" i "-".
-20-
Tablica 2
------------------------------------------
| Operator | Associativnost' |
|____________________|___________________|
| () [] -> . | sleva napravo |
|____________________|___________________|
| ~ ++ -- - f | sprava nalevo |
|(type) * & sizeof| |
|____________________|___________________|
| * / % | sleva napravo |
|____________________|___________________|
| + - | sleva napravo |
|____________________|___________________|
| << >> | sleva napravo |
|____________________|___________________|
| < <= > >= | sleva napravo |
|____________________|___________________|
| == != | sleva napravo |
|____________________|___________________|
| & | sleva napravo |
|____________________|___________________|
| ^ | sleva napravo |
|____________________|___________________|
| | | sleva napravo |
|____________________|___________________|
| && | sleva napravo |
|____________________|___________________|
| || | sleva napravo |
|____________________|___________________|
| ?: | sprava nalevo |
|____________________|___________________|
| = += -= i t.p. | sprava nalevo |
|____________________|___________________|
| , | sleva napravo |
|____________________|___________________|
Otmetim, chto uroven' starshinstva pobitovyh logicheskih
operacij &, ^ i | nizhe urovnya operacij == i !=. |to privodit
k tomu, chto osushchestvlyayushchie pobitovuyu proverku vyrazheniya,
podobnye
if ((h & mask) == 0) ...
dlya polucheniya pravil'nyh rezul'tatov dolzhny zaklyuchat'sya v
kruglye skobki, v protivnom sluchae ono budet ponyato tak:
vyrazhenie: x & mask == 0
ponyato kak: x & ( mask == 0 )
-21-
Opisaniya ispol'zuyutsya dlya ukazaniya interpretacii, koto-
ruyu yazyk Si budet davat' kazhdomu identifikatoru; oni ne obya-
zatel'no rezerviruyut pamyat', sootvetstvuyushchuyu identifikatoru.
Opisaniya imeyut formu
opisanie:
specifikatory_opisaniya spisok_opisatelej;
neob
Opisateli v spiske opisatelej soderzhat opisyvaemye identifi-
katory. Specifikatory opisaniya predstavlyayut soboj posledo-
vatel'nost' specifikatorov tipa i specifikatorov klassa
pamyati.
specifikatory_opisaniya:
s_tipa s_opisaniya
neob
s_klassa_pamyati s_opisaniya
neob
gde c_... - specifikator_...
Spisok opisatelej dolzhen byt' soglasovannym v smysle, opisy-
vaemom nizhe.
5.1. Specifikatory klassa pamyati
nizhe perechislyayutsya specifikatory klassa pamyati:
specifikator_klassa_pamyati:
auto
static
extern
register
typedef
Specifikator typedef ne rezerviruet pamyat' i nazyvaetsya
"specifikatorom klassa pamyati" tol'ko po sintaksicheskim
soobrazheniyam; eto obsuzhdaetsya nizhe. Smysl razlichnyh klassov
pamyati byl obsuzhden ranee (sm. "Ob容kty yazyka Si").
Opisaniya auto, static i register sluzhat takzhe v
kachestve opredelenij v tom smysle, chto oni vyzyvayut rezervi-
rovanie nuzhnogo kolichestva pamyati. V sluchae extern dolzhno
prisutstvovat' vneshnee opredelenie ukazyvaemyh identifikato-
rov gde to vne funkcii, v kotoroj oni opisany.
Opisanie register luchshe vsego predstavlyat' sebe kak
opisanie auto vmeste s namekom kompilyatoru, chto opisannye
takim obrazom peremennye budut chasto ispol'zovat'sya. |ffek-
tivny tol'ko neskol'ko pervyh takih opisanij. Krome togo, v
-22-
registrah mogut hranit'sya tol'ko peremennye opredelennyh
tipov; na CM-|VM eto int, char ili ukazatel'. Sushchestvuet i
drugoe ogranichenie na ispol'zovanie registrovyh peremennyh:
k nim nel'zya primenyat' operaciyu vzyatiya adresa &. Pri razum-
nom ispol'zovanii registrovyh opisanij mozhno ozhidat' poluche-
niya men'shih po razmeru i bolee bystryh programm, no v budu-
shchem uluchshenie generirovaniya kodov mozhet sdelat' ih nenuzh-
nymi.
V kompilyatore dlya SM |VM vosprinimayutsya pervye 3 opisa-
niya register v kazhdoj funkcii.
Opisanie mozhet soderzhat' ne bolee odnogo specifikatora
klassa pamyati. Esli opisanie ne soderzhit specifikatora
klassa pamyati, to schitaetsya, chto on imeet znachenie auto,
esli opisanie nahoditsya vnutri nekotoroj funkcii, i extern v
protivnom sluchae. Isklyuchenie: funkcii nikogda ne byvayut
avtomaticheskimi.
Nizhe perechislyayutsya specifikatory tipa.
specifikator_tipa:
char
short
int
long
unsigned
float
double
specifikator_struktury_ili_ob容dineniya
specifikator_perechisleniya
opredelyayushchee_tip_imya
Slova long, short i unsigned mozhno rassmatrivat' kak prila-
gatel'nye; dopustimy sleduyushchie kombinacii:
short int
long int
unsigned int
long float
Poslednyaya kombinaciya oznachaet to zhe, chto i double. V ostal'-
nom opisanie mozhet soderzhat' ne bolee odnogo specifikatora
tipa. Esli opisanie ne soderzhit specifikatora tipa, to schi-
taetsya, chto on imeet znachenie int.
Specifikatory struktur i ob容dinenij obsuzhdayutsya v p.
0.5, specifikaciya perechislimogo tipa - v p.0.6; opisaniya s
opredelyayushchimi tip imenami typedef obsuzhdayutsya v p. 0.9.
-23-
Vhodyashchij v opisanie spisok opisatelej predstavlyaet
soboj posledovatel'nost' razdelennyh zapyatymi opisatelej,
kazhdyj iz kotoryh mozhet imet' inicializator.
spisok_opisatelej:
inicializiruemyj_opisatel'
inicializiruemyj_opisatel',spi-
sok_opisatelej
inicializiruemyj_opisatel':
opisatel' inicializator
neob
Inicializatory opisyvayutsya v p.0.6. Specifikatory i opisaniya
ukazyvayut tip i klass pamyati ob容ktov, na kotorye ssylayutsya
opisateli. Opisateli imeyut sleduyushchij sintaksis:
opisatel':
identifikator
( opisatel' )
* opisatel'
opisatel' ()
opisatel' [konstantnoe-vyrazhenie]
neob
Gruppirovanie takoe zhe, kak i v vyrazheniyah.
Kazhdyj opisatel' rassmatrivaetsya kak utverzhdenie togo,
chto kogda konstrukciya toj zhe samoj formy, chto i opisatel',
poyavlyaetsya v vyrazhenii, to ona vydaet ob容kt ukazannogo tipa
i ukazannogo klassa pamyati. Kazhdyj opisatel' soderzhit rovno
odin identifikator; eto imenno tot identifikator, kotoryj i
opisyvaetsya.
Esli v kachestve opisatelya poyavlyaetsya prosto identifika-
tor, to on imeet tip, ukazyvaemyj v specificiruyushchem zago-
lovke opisaniya.
Opisatel' v kruglyh skobkah identichen opisatelyu bez
kruglyh skobok, no kruglye skobki mogut izmenyat' svyazi v
sostavnyh opisatelyah. Primery smotri nizhe.
Predstavim sebe opisanie
t di
gde t - specifikator tipa (podobnyj int i t.d.), a di - opi-
satel'. Predpolozhim, chto eto opisanie privodit k tomu, chto
sootvetstvuyushchij identifikator imeet tip ...t, gde "..."
pusto, esli di prosto otdel'nyj identifikator (tak chto tip h
-24-
v int h prosto int). Togda, esli di imeet formu
*d
to soderzhashchijsya identifikator budet imet' tip ... ukazatel'
na t.
Esli di imeet formu
d()
to soderzhashchijsya identifikator imeet tip ... funkciya, vozvra-
shchayushchaya t.
Esli di imeet formu
d[konstantnoe_vyrazhenie]
ili
d[ ]
to soderzhashchijsya identifikator imeet tip ... massiv t. V per-
vom sluchae konstantnym vyrazheniem yavlyaetsya vyrazhenie, znache-
nie kotorogo mozhno opredelit' vo vremya kompilyacii i kotoroe
imeet tip int. (tochnoe opredelenie konstantnogo vyrazheniya
dano nizhe). Kogda neskol'ko specifikacij vida "massiv iz"
okazyvayutsya primykayushchimi, to sozdaetsya mnogomernyj massiv;
konstantnoe vyrazhenie, zadayushchee granicy massivov, mozhet
otsutstvovat' tol'ko u pervogo chlena etoj posledovatel'-
nosti. Takoe opuskanie polezno, kogda massiv yavlyaetsya vnesh-
nim ili formal'nym i ego fakticheskoe opredelenie, kotoroe
vydelyaet pamyat', privoditsya v drugom meste. Pervoe konstant-
noe vyrazhenie mozhet byt' opushcheno takzhe togda, kogda za opi-
satelem sleduet inicializaciya. V etom sluchae razmer oprede-
lyaetsya po chislu privedennyh inicializiruemyh elementov.
Massiv mozhet byt' obrazovan iz elementov odnogo iz
osnovnyh tipov, iz ukazatelej, iz struktur ili ob容dinenij
ili iz drugih massivov (chtoby obrazovat' mnogomernyj mas-
siv).
Ne vse vozmozhnosti, kotorye razresheny s tochki zreniya
ukazannogo vyshe sintaksisa, fakticheski dopustimy. Imeyutsya
sleduyushchie ogranicheniya: funkcii ne mogut vozvrashchat' massivy
ili funkcii, hotya oni mogut vozvrashchat' ukazateli na takie
veshchi; ne sushchestvuet massivov funkcij, hotya mogut byt' mas-
sivy ukazatelej na funkcii. Analogichno, struktury ili ob容-
dineniya ne mogut soderzhat' funkciyu, no oni mogut soderzhat'
ukazatel' na funkciyu.
V kachestve primera rassmotrim opisanie
-25-
int i, *ip, f(), *fip(), (*pfi)();
v kotorom opisyvaetsya celoe i, ukazatel' ip na celoe, funk-
ciya f, vozvrashchayushchaya celoe, funkciya fip, vozvrashchayushchaya ukaza-
tel' na celoe, i ukazatel' pfi na funkciyu, kotoraya vozvra-
shchaet celoe. Osobenno polezno sravnit' dva poslednih opisa-
telya. Svyaz' v *fip() mozhno predstavit' v vide *(fip()), tak
chto opisaniem predpolagaetsya, chto v vyrazhenii trebuetsya
obrashchenie k funkcii fip i posleduyushchee ispol'zovanie kosven-
noj adresacii dlya vydachi s pomoshch'yu poluchennogo rezul'tata
(ukazatelya) celogo. V opisatele (*pfi)() dopolnitel'nye
skobki neobhodimy, poskol'ku oni tochno tak zhe, kak i v vyra-
zhenii, ukazyvayut, chto kosvennaya adresaciya cherez ukazatel'
vydaet funkciyu, kotoraya zatem vyzyvaetsya; eta vyzvannaya
funkciya vozvrashchaet celoe.
V kachestve drugogo primera privedem opisanie
float fa[17], *afp[17];
v kotorom opisyvaetsya massiv chisel tipa float i massiv uka-
zatelej na chisla tipa float. Nakonec,
static int h3d[3][5][7];
opisyvaet staticheskij trehmernyj massiv celyh razmerom
3*5*7. Bolee podrobno: h3d yavlyaetsya massivom iz treh elemen-
tov; kazhdyj element yavlyaetsya massivom pyati massivov; kazhdyj
poslednij massiv yavlyaetsya massivom iz semi celyh. Kazhdoe iz
vyrazhenij h3d, h3d[i], h3d[i][j] i h3d[i][j][k] mozhet razum-
nym obrazom poyavlyat'sya v vyrazheniyah. Pervye tri imeyut tip
"massiv", poslednee imeet tip int.
5.5. Opisanie struktur i ob容dinenij
Struktura - eto ob容kt, sostoyashchij iz posledovatel'nosti
imenovannyh chlenov. Kazhdyj chlen mozhet byt' proizvol'nogo
tipa. Ob容dinenie - eto ob容kt, kotoryj v dannyj moment
mozhet soderzhat' lyuboj iz neskol'kih chlenov. Specifikatory i
ob容dineniya imeyut odinakovuyu formu.
specifikator_struktury_ili_ob容dineniya:
struktura_ili_ob容dinenie { spi-
sok_opisanij_struktury }
identifikator_struktury_ili_ob容dine-
niya { spisok-opisanij-struktury }
identifikator_struktury_ili_ob容dineniya
struktura_ili_ob容dinenie:
struct
union
-26-
Spisok_opisanij_struktury yavlyaetsya posledovatel'nost'yu opi-
sanij chlenov struktury ili ob容dineniya:
spisok_opisanij_struktury:
opisanie_struktury
opisanie_struktury spi-
sok_opisanij_struktury
opisanie_struktury:
specifikator_tipa spi-
sok_opisatelej_struktury
spisok_opisatelej_struktury:
opisatel'_struktury
opisatel'_struktury,spisok_opi-
satelej_struktury
V obychnom sluchae opisatel' struktury yavlyaetsya prosto opisa-
telem chlena struktury ili ob容dineniya. CHlen struktury mozhet
takzhe sostoyat' iz specificirovannogo chisla bitov. Takoj
chlen nazyvaetsya takzhe polem; ego dlina otdelyaetsya ot imeni
polya dvoetochiem.
opisatel'_struktury:
opisatel'
opisatel': konstantnoe_vyrazhenie
: konstantnoe_vyrazhenie
Vnutri struktury opisannye v nej ob容kty imeyut adresa, koto-
rye uvelichivayutsya v sootvetstvii s chteniem opisanij ob容ktov
sleva napravo. Kazhdyj chlen struktury, kotoryj ne yavlyaetsya
polem, nachinaetsya s adresnoj granicy, sootvetstvuyushchej ego
tipu; sledovatel'no v strukture mogut okazat'sya neimenovan-
nye dyry. CHleny, yavlyayushchiesya polyami, pomeshchayutsya v mashinnye
celye; oni ne perekryvayut granicy slova. Pole, kotoroe ne
umeshchaetsya v ostavshemsya v dannom slove prostranstve, pomeshcha-
etsya v sleduyushchee slovo. Polya vydelyayutsya sprava nalevo na
CM-|VM, no mogut vydelyat'sya sleva napravo na drugih mashinah.
Opisatel' struktury, kotoryj ne soderzhit opisatelya, a
tol'ko dvoetochie i shirinu, ukazyvaet neimenovannoe pole,
poleznoe dlya zapolneniya svobodnogo prostranstva s cel'yu
sootvetstviya zadavaemym izvne shemam. Special'nyj sluchaj
neimenovannogo polya s shirinoj 0 ispol'zuetsya dlya ukazaniya o
vyravnivanii sleduyushchego polya na granicu slova. Pri etom
predpolagaetsya, chto "sleduyushchee pole" dejstvitel'no yavlyaetsya
polem, a ne obychnym chlenom struktury, poskol'ku v poslednem
sluchae vyravnivanie osushchestvlyaetsya avtomaticheski.
Sam yazyk ne nakladyvaet ogranichenij na tipy ob容ktov,
opisannyh kak polya, no ot realizacij ne trebuetsya obespechi-
vat' chto-libo otlichnoe ot celyh polej. Bolee togo, dazhe polya
-27-
tipa int mogut rassmatrivat'sya kak ne imeyushchie znaka. Na CM-
|VM polya ne imeyut znaka i mogut prinimat' tol'ko celye zna-
cheniya. Vo vseh realizaciyah otsutstvuyut massivy polej i k
polyam ne primenima operaciya vzyatiya adresa &, tak chto ne
sushchestvuet i ukazatelej na polya.
Ob容dinenie mozhno predstavit' sebe kak strukturu, vse
chleny kotoroj nachinayutsya so smeshcheniya 0 i razmer kotoroj dos-
tatochen, chtoby soderzhat' lyuboj iz ee chlenov. V kazhdyj moment
ob容dinenie mozhet soderzhat' ne bolee odnogo iz svoih chlenov.
Specifikator struktury ili ob容dineniya vo vtoroj forme,
t.e. odin iz:
struct ident {spisok_opisanij_struktury}
union ident {spisok-opisanij-struktury}
opisyvaet ident v kachestve yarlyka struktury (ili yarlyka
ob容dineniya) dlya struktury, specificirovannoj etim spiskom.
Posleduyushchee opisanie mozhet zatem ispol'zovat' tret'yu formu
specifikatora, odin iz
struct ident
union ident
YArlyki struktur dayut vozmozhnost' opredeleniya struktur, koto-
rye ssylayutsya na samih sebya; oni takzhe pozvolyayut neodnok-
ratno ispol'zovat' privedennuyu tol'ko odin raz dlinnuyu chast'
opisaniya. Zapreshchaetsya opisyvat' strukturu ili ob容dinenie,
kotorye soderzhat obrazec samogo sebya, no struktura ili ob容-
dinenie mogut soderzhat' ukazatel' na strukturu ili ob容dine-
nie takogo zhe vida, kak oni sami.
Imena chlenov i yarlykov struktur mogut sovpadat' s ime-
nami obychnyh peremennyh. Odnako imena yarlykov i chlenov
dolzhny byt' vzaimno razlichnymi.
Dve struktury mogut imet' obshchuyu nachal'nuyu posledova-
tel'nost' chlenov; eto oznachaet, chto tot zhe samyj chlen mozhet
poyavit'sya v dvuh razlichnyh strukturah, esli on imeet odina-
kovyj tip v obeih strukturah i esli vse predydushchie chleny
obeih struktur odinakovy. Fakticheski kompilyator tol'ko pro-
veryaet, chto imya v dvuh razlichnyh strukturah imeet odinakovyj
tip i odinakovoe smeshchenie, no esli predshestvuyushchie chleny
otlichayutsya, to konstrukciya okazyvaetsya neperenosimoj.
Vot prostoj primer opisaniya struktury:
-28-
struct tnode {
char tword[20];
int count;
struct tnode *left;
struct tnode *right;
};
takaya struktura soderzhit massiv iz 20 simvolov, celoe i dva
ukazatelya na takie zhe struktury. Kak tol'ko privedeno takoe
opisanie, opisanie
struct tnode s, *sp;
govorit o tom, chto s yavlyaetsya strukturoj ukazannogo vida, a
sp yavlyaetsya ukazatelem na strukturu ukazannogo vida. Pri
nalichii etih opisanij vyrazhenie
sp->count
ssylaetsya na pole count struktury, na kotoruyu ukazyvaet sp;
vyrazhenie
s.left
ssylaetsya na ukazatel' levogo poddereva v strukture s, a
vyrazhenie
s.right->tword[0]
ssylaetsya na pervyj simvol chlena tword pravogo poddereva iz
s.
Perechislimyj tip dannyh analogichen skalyarnym tipam
yazyka Paskal'. Specifikator perechislimogo tipa imeet sledu-
yushchij vid:
specifikator_perechisleniya:
enum spisok_perechisleniya
enum identifikator spisok_perechisleniya
enum identifikator
spisok_perechisleniya:
perechislyaemoe
spisok_perechisleniya, perechislyaemoe
perechislyaemoe:
identifikator
identifikator = konstantnoe vyrazhenie
-29-
Rol' identifikatora v specifikatore_perechisleniya pol-
nost'yu analogichna roli yarlyka struktury v
specifikatore_struktury; identifikator oboznachaet opredelen-
noe perechislenie. Naprimer, opisanie
enum color {red, white, black, blue };
. . .
enum color *cp, col;
ob座avlyaet identifikator color yarlykom perechisleniya tipa,
opisyvayushchego razlichnye cveta i zatem ob座avlyaet cr ukazatelem
na ob容kt etogo tipa, a col - ob容ktom etogo tipa.
Identifikatory v spiske_perechisleniya stanovyatsya kons-
tantami i mogut poyavlyat'sya tam, gde trebuyutsya (po kontekstu)
konstanty. Esli ne ispol'zuetsya vtoraya forma perechislyaemogo
(s ravenstvom =), to velichiny konstant nachinayutsya s 0 i voz-
rastayut na 1 v sootvetstvii s prochteniem ih opisaniya sleva
napravo. Perechislyaemoe s prisvoeniem = pridaet sootvetstvuyu-
shchemu identifikatoru ukazannuyu velichinu; posleduyushchie identi-
fikatory prodolzhayut progressiyu ot pripisannoj velichiny.
YArlyki perechislenij i imena konstant dolzhny byt' raz-
lichnymi i ne sovpadat' s imenami yarlykov i chlenov struktur.
Ob容kty dannogo tipa perechisleniya rassmatrivayutsya kak
ob容kty, imeyushchie tip, otlichnyj ot lyubyh tipov i kontroliruyu-
shchaya programma lint soobshchaet ob oshibkah nesootvetstviya tipov.
V realizacii na CM_|VM so vsemi perechislyaemymi peremennymi
operiruyut tak, kak esli by oni imeli tip int.
Opisatel' mozhet ukazyvat' nachal'noe znachenie opisyvae-
mogo identifikatora. Inicializator sostoit iz vyrazheniya ili
zaklyuchennogo v figurnye skobki spiska znachenij, pered koto-
rymi stavitsya znak =.
inicializator:
= vyrazhenie
= {spisok_inic}
= {spisok_inic,}
spisok_inic:
vyrazhenie
spisok_inic,spisok_inic
{spisok_inic}
gde
spisok_inic - spisok_inicializatorov
-30-
Vse vyrazheniya, vhodyashchie v inicializator staticheskoj ili
vneshnej peremennoj, dolzhny byt' libo konstantnymi vyrazheni-
yami, libo vyrazheniyami, kotorye svodyatsya k adresu ranee opi-
sannoj peremennoj, smeshchennomu na konstantnoe (vozmozhno,
nulevoe) vyrazhenie. Avtomaticheskie i registrovye peremennye
mogut byt' inicializirovany proizvol'nymi vyrazheniyami, vklyu-
chayushchimi konstanty i ranee opisannye peremennye i funkcii.
Garantiruetsya, chto neinicializirovannye staticheskie i
vneshnie peremennye poluchayut v kachestve nachal'nyh znachenij 0;
neinicializirovannye avtomaticheskie i registrovye peremennye
v kachestve nachal'nyh znachenij soderzhat musor.
Kogda inicializator primenyaetsya k skalyaru (ukazatelyu
ili ob容ktu arifmeticheskogo tipa), to on sostoit iz odnogo
vyrazheniya, vozmozhno zaklyuchennogo v figurnye skobki. Nachal'-
noe znachenie ob容kta nahoditsya iz vyrazheniya; vypolnyayutsya te
zhe samye preobrazovaniya, chto i pri prisvaivanii.
Kogda opisyvaemaya peremennaya yavlyaetsya agregatom (struk-
turoj ili massivom), to inicializator sostoit iz zaklyuchen-
nogo v figurnye skobki i razdelennogo zapyatymi spiska inici-
alizatorov dlya chlenov agregata. |tot spisok sostavlyaetsya v
poryadke vozrastaniya indeksa ili v sootvetstvii s poryadkom
chlenov. Esli agregat soderzhit podagregaty, to eto pravilo
primenyaetsya rekursivno k chlenam agregata. Esli kolichestvo
inicializatorov v spiske okazyvaetsya men'she chisla chlenov
agregata, to ostavshiesya chleny agregata zapolnyayutsya nulyami.
Zapreshchaetsya inicializirovat' ob容dineniya ili avtomaticheskie
agregaty.
Figurnye skobki mogut interpretirovat'sya sleduyushchim
obrazom. Esli inicializator nachinaetsya s levoj figurnoj
skobki, to posleduyushchij razdelennyj zapyatymi spisok iniciali-
zatorov inicializiruet chleny agregata; budet oshibkoj, esli v
spiske okazhetsya bol'she inicializatorov, chem chlenov agregata.
Esli odnako inicializator ne nachinaetsya s levoj figurnoj
skobki, to iz spiska beretsya tol'ko nuzhnoe dlya chlenov dan-
nogo agregata chislo elementov; ostavshiesya elementy ispol'zu-
yutsya dlya inicializacii sleduyushchego chlena agregata, chast'yu
kotorogo yavlyaetsya nastoyashchij agregat. Sledovatel'no, skobki v
nekotoryh sluchayah mozhno opuskat'.
Poslednee sokrashchenie dopuskaet vozmozhnost' inicializa-
cii massiva tipa char s pomoshch'yu stroki. V etom sluchae chleny
massiva posledovatel'no inicializiruyutsya simvolami stroki.
Naprimer,
int h[] = {1,3,5};
opisyvaet i inicializiruet h kak odnomernyj massiv; pos-
kol'ku razmer massiva ne specificirovan, a spisok
-31-
inicializatora soderzhit tri elementa, schitaetsya, chto massiv
sostoit iz treh chlenov.
Vot primer inicializacii s polnym ispol'zovaniem figur-
nyh skobok:
float *y[4][3] = {
( 1, 3, 5 ),
( 2, 4, 6 ),
( 3, 5, 7 ),
};
Zdes' 1, 3 i 5 inicializiruyut pervuyu stroku massiva y[0], a
imenno y[0][0], y[0][1] i y[0][2]. Analogichnym obrazom sle-
duyushchie dve strochki inicializiruyut y[1] i y[2]. Inicializator
zakanchivaetsya prezhdevremenno, i, sledovatel'no, massiv y[3]
inicializiruetsya nulyami. V tochnosti takogo zhe effekta mozhno
bylo by dostich', napisav
float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
Inicializator dlya y nachinaetsya s levoj figurnoj skobki, no
inicializatora dlya y[0] net. Poetomu ispol'zuetsya 3 elementa
iz spiska. Analogichno sleduyushchie tri elementa ispol'zuyutsya
posledovatel'no dlya y[1] i y[2]. Sleduyushchee opisanie
float y[4][3] = {
{1}, {2}, {3}, {4}
};
inicializiruet pervyj stolbec y (esli ego rassmatrivat' kak
dvumernyj massiv), a ostal'nye elementy zapolnyayutsya nulyami.
I nakonec, opisanie
char msg[] = "syntax error on line %s\n";
demonstriruet inicializaciyu elementov simvol'nogo massiva s
pomoshch'yu stroki.
V dvuh sluchayah (dlya yavnogo ukazaniya tipa preobrazovaniya
v konstrukcii perevoda i dlya argumentov operacii sizeof)
zhelatel'no imet' vozmozhnost' zadavat' tip dannyh. |to osu-
shchestvlyaetsya s pomoshch'yu "imeni tipa", kotoroe po sushchestvu
yavlyaetsya opisaniem ob容kta takogo tipa, v kotorom opushcheno
imya samogo ob容kta.
-32-
Imya tipa:
specifikator_tipa abstraktnyj_opisatel'
abstraktnyj_opisatel':
pusto
(abstraktnyj_opisatel')
*abstraktnyj opisatel'
abstraktnyj_opisatel' ()
abstraktnyj_opisatel' [konstant-
noe vyrazhenie]
neob
Vo izbezhanie dvusmyslennosti v konstrukcii
(abstraktnyj_opisatel')
trebuetsya, chtoby abstraktnyj_opisatel' byl nepust. Pri etom
ogranichenii vozmozhno odnoznachno opredelit' to mesto v
abstraktnom_opisatele, gde dolzhen poyavit'sya identifikator,
esli by eta konstrukciya byla opisatelem v opisanii. Imeno-
vannyj tip sovpadaet togda s tipom gipoteticheskogo identifi-
katora. Naprimer, imena tipov
int
int *
int *[3]
int (*)[3]
int *()
int (*)()
imenuyut sootvetstvenno tipy "celyj", "ukazatel' na celoe",
"massiv iz treh ukazatelej na celoe", "ukazatel' na massiv
iz treh celyh", " funkciya, vozvrashchayushchaya ukazatel' na celoe"
i "ukazatel' na funkciyu, vozvrashchayushchuyu celoe".
Opisaniya, v kotoryh "klass pamyati" specificirovan kak
typedef, ne vyzyvayut vydeleniya pamyati. Vmesto etogo oni
opredelyayut identifikatory, kotorye pozdnee mozhno ispol'zo-
vat' tak, slovno oni yavlyayutsya klyuchevymi slovami, imeyushchimi
osnovnye ili proizvodnye tipy.
opredelyayushchee_tip_imya:
identifikator
V predelah oblasti dejstviya opisaniya so specifikatorom
typedef kazhdyj identifikator, opisannyj v nem, stanovitsya
sintaksicheski ekvivalentnym klyuchevomu slovu, imeyushchemu tot
tip, kotoryj associiruet s identifikatorom v opisannom v p.
0.4 smysle. Naprimer, posle opisanij
typedef int miles, *klicksp;
typedef struct { double re, im;} complex;
-33-
konstrukcii
miles distance;
extern klicksp metricp;
complex z, *zp;
stanovyatsya zakonnymi opisaniyami; pri etom tipom distance
yavlyaetsya int, tipom metricp - "ukazatel' na int", tipom z -
specificirovannaya struktura i tipom zp - ukazatel' na takuyu
strukturu.
Specifikator typedef ne vvodit kakih-libo sovershenno
novyh tipov, a tol'ko opredelyaet sinonimy dlya tipov, kotorye
mozhno bylo by specificirovat' i drugim sposobom. Tak v pri-
vedennom vyshe primere peremennaya distance schitaetsya imeyushchej
tochno takoj zhe tip, chto i lyuboj drugoj ob容kt, opisannyj v
int.
Za isklyucheniem osobo ogovarivaemyh sluchaev, operatory
vypolnyayutsya posledovatel'no.
6.1. Operatornoe vyrazhenie
bol'shinstvo operatorov yavlyayutsya operatornymi vyrazheni-
yami, kotorye imeyut formu
vyrazhenie;
Obychno operatornye vyrazheniya yavlyayutsya prisvaivaniyami ili
obrashcheniyami k funkciyam.
6.2. Sostavnoj operator (ili blok)
S tem, chtoby dopustit' vozmozhnost' ispol'zovaniya nes-
kol'kih operatorov tam, gde ozhidaetsya prisutstvie tol'ko
odnogo, predusmatrivaetsya sostavnoj operator (kotoryj takzhe
nazyvayut "blokom"):
sostavnoj operator:
{spisok_opisanij spisok_operatorov}
neob neob
spisok_opisanij:
opisanie
opisanie spisok_opisanij
spisok_operatorov:
operator
operator spisok_operatorov
Esli kakoj-libo identifikator iz spiska_opisanij byl opisan
-34-
ranee, to vo vremya vypolneniya bloka vneshnee opisanie podav-
lyaetsya i snova vstupaet v silu posle vyhoda iz bloka.
Lyubaya inicializaciya avtomaticheskih i registrovyh pere-
mennyh provoditsya pri kazhdom vhode v blok cherez ego nachalo.
V kompilyatore OS DEMOS razreshaetsya (no eto plohaya praktika)
peredavat' upravlenie vnutr' bloka; v takom sluchae eti ini-
cializacii ne vypolnyayutsya. Inicializacii staticheskih pere-
mennyh provodyatsya tol'ko odin raz, kogda nachinaetsya vypolne-
nie programmy.
Nahodyashchiesya vnutri bloka vneshnie opisaniya ne rezervi-
ruyut pamyati, tak chto ih inicializaciya ne razreshaetsya.
Imeyutsya dve formy uslovnyh operatorov:
if (vyrazhenie) operator
if (vyrazhenie) operator else operator
V oboih sluchayah vychislyaetsya vyrazhenie i, esli ono otlichno ot
nulya, to vypolnyaetsya pervyj podoperator. Vo vtorom sluchae,
esli vyrazhenie ravno nulyu, vypolnyaetsya vtoroj podoperator.
Kak obychno, dvusmyslennost' else razreshaetsya svyazyvaniem
else s poslednim vstrechayushchimsya if, u kotorogo net else.
Operator while imeet formu
while (vyrazhenie) operator
Podoperator vypolnyaetsya povtorno do teh por, poka znachenie
vyrazheniya ostaetsya otlichnym ot nulya. Proverka proizvoditsya
pered kazhdym vypolneniem operatora.
Operator do imeet formu
do operator while (vyrazhenie)
Operator vypolnyaetsya povtorno do teh por, poka znachenie
vyrazheniya ne stanet ravnym nulyu. Proverka proizvoditsya posle
kazhdogo vypolneniya operatora.
Operator for imeet formu
(vyrazhenie1;vyrazhenie2;vyrazhenie3)operator
neob neob neob
-35-
Operator for ekvivalenten sleduyushchemu:
vyrazhenie1;
while (vyrazhenie2) {
operator
vyrazhenie3;
}
Takim obrazom, pervoe vyrazhenie opredelyaet inicializaciyu
cikla; vtoroe specificiruet proverku, vypolnyaemuyu pered kazh-
doj iteraciej, tak chto vyhod iz cikla proishodit togda,
kogda znachenie vyrazheniya stanovitsya nulem; tret'e vyrazhenie
chasto zadaet prirashchenie parametra, kotoryj vychislyaetsya posle
kazhdoj iteracii.
Lyuboe vyrazhenie ili vse oni mogut byt' opushcheny. Esli
otsutstvuet vtoroe vyrazhenie, to predlozhenie s while schita-
etsya ekvivalentnym while(1); drugie otsutstvuyushchie vyrazheniya
prosto opuskayutsya iz privedennogo vyshe rasshireniya.
Operator switch (pereklyuchatel'), vyzyvaet peredachu
upravleniya k odnomu iz neskol'kih operatorov, v zavisimosti
ot znacheniya vyrazheniya. Operator imeet formu
switch (vyrazhenie) operator
V vyrazhenii provodyatsya obychnye arifmeticheskie preobrazova-
niya, rezul'tat dolzhen imet' tip int. Operator obychno yavlya-
etsya sostavnym. Lyuboj operator vnutri etogo operatora mozhet
byt' pomechen odnim ili bolee variantnym prefiksom case, ime-
yushchim formu:
case konstantnoe vyrazhenie:
Gde konstantnoe vyrazhenie dolzhno imet' tip int. Nikakie dve
variantnye konstanty v odnom i tom zhe pereklyuchatele ne mogut
imet' odinakovoe znachenie. Tochnoe opredelenie konstantnogo
vyrazheniya privoditsya nizhe.
Krome togo, mozhet prisutstvovat' odin operatornyj pre-
fiks vida
default:
Pri vypolnenii operatora switch vychislyaetsya vhodyashchee v
nego vyrazhenie i sravnivaetsya s kazhdoj variantnoj konstan-
toj. Esli odna iz variantnyh konstant okazyvaetsya ravnoj
znacheniyu etogo vyrazheniya, to upravlenie peredaetsya opera-
toru, kotoryj sleduet za sovpadayushchim variantnym prefiksom.
Esli ni odna iz variantnyh konstant ne sovpadaet so
-36-
znacheniem vyrazheniya i esli pri etom prisutstvuet prefiks
default, to upravlenie peredaetsya operatoru, pomechennomu
etim prefiksom. Esli ni odin iz variantov ne podhodit i pre-
fiks default otsutstvuet, to ni odin iz operatorov v perek-
lyuchatele ne vypolnyaetsya.
Sami po sebe prefiksy case i default ne izmenyayut vypol-
neniya programmy, programma vypolnyaetsya posledovatel'no, poka
ne vstretitsya yavnaya peredacha upravleniya. Dlya vyhoda iz
pereklyuchatelya imeetsya operator break (p.0.8).
Obychno operator, kotoryj vhodit v pereklyuchatel', yavlya-
etsya sostavnym. Opisaniya mogut poyavlyat'sya v nachale etogo
operatora, no inicializacii avtomaticheskih i registrovyh
peremennyh budut neeffektivnymi.
Primer:
switch (regim) {
case 'x': regx++;
case 'X': case 'Y': regY++; break;
case '-': regx = 0; break;
default: err("Oshibka"); goto next;
}
Operator
break;
vyzyvaet zavershenie vypolneniya naimen'shego ohvatyvayushchego
etot operator operatora while, do, for ili switch; upravle-
nie peredaetsya operatoru, sleduyushchemu za zavershennym operato-
rom.
Operator
continue;
privodit k peredache upravleniya na prodolzhayushchuyu cikl chast'
naimen'shego ohvatyvayushchego etot operator operatora while, do
ili for; to est' na konec cikla. Bolee tochno, v kazhdom iz
operatorov
while(...) { | do { | for(...) {
... | ... | ...
contin: ; | contin: ; | contin: ;
} | } while(...); | }
-37-
operator continue ekvivalenten operatoru goto contin. (Za
contin: sleduet pustoj operator; sm. p. 0.13.).
Vozvrashchenie iz funkcii v vyzyvayushchuyu programmu osushchestv-
lyaetsya s pomoshch'yu operatora return, kotoryj imeet odnu iz
sleduyushchih form
return;
return vyrazhenie;
V pervom sluchae vozvrashchaemoe znachenie neopredeleno. Vo vto-
rom sluchae v vyzyvayushchuyu funkciyu vozvrashchaetsya znachenie vyra-
zheniya. Esli trebuetsya, vyrazhenie preobrazuetsya k tipu funk-
cii, v kotoroj ono poyavlyaetsya, kak v sluchae prisvaivaniya.
Popadanie na konec funkcii ekvivalentno vozvratu bez vozvra-
shchaemogo znacheniya.
Vozvrashchat' mozhno znachenie arifmeticheskogo tipa, a takzhe
strukturu (no ne massiv).
Upravlenie mozhno peredavat' bezuslovno s pomoshch'yu opera-
tora
goto identifikator1
Identifikator dolzhen byt' metkoj (p. 0.12), lokalizovannoj v
dannoj funkcii.
6.12. Pomechennyj operator
Pered lyubym operatorom mozhet stoyat' metka, imeyushchaya vid:
identifikator:
Metki ispol'zuyutsya tol'ko dlya ukazaniya mesta, kuda pereda-
etsya upravlenie operatorom goto. Oblast'yu dejstviya metki
yavlyaetsya dannaya funkciya, za isklyucheniem teh podblokov, v
kotoryh tot zhe identifikator opisan snova.
Pustoj operator imeet formu:
;
Pustoj operator okazyvaetsya poleznym, tak kak on pozvolyaet
postavit' metku pered zakryvayushchej skobkoj } sostavnogo ope-
ratora ili ukazat' pustoe telo v operatorah cikla, takih kak
while.
-38-
* 7. VNESHNIE OPREDELENIYA
Si-programma predstavlyaet soboj posledovatel'nost'
vneshnih opredelenij. Vneshnee opredelenie opisyvaet identifi-
kator kak imeyushchij klass pamyati extern (po umolchaniyu), ili,
vozmozhno, static, i specificirovannyj tip. Specifikator tipa
takzhe mozhet byt' pustym; v etom sluchae schitaetsya, chto tip
yavlyaetsya tipom int. Oblast' dejstviya vneshnih opredelenij
rasprostranyaetsya do konca fajla, v kotorom oni privedeny,
tochno tak zhe, kak vliyanie opisanij prostiraetsya do konca
bloka. Sintaksis vneshnih opredelenij ne otlichaetsya ot sin-
taksisa opisanij, za isklyucheniem togo, chto tol'ko na etom
urovne mozhno privodit' tekst funkcij.
7.1. Vneshnee opredelenie funkcii
Opredelenie funkcii imeet formu
opredelenie_funkcii:
specifikatory_opisaniya opisa-
neob
tel'_funkcii telo_funkcii
Edinstvennymi specifikatorami klassa pamyati, dopuskaemymi v
kachestve specifikatorov-opisaniya, yavlyayutsya extern ili
static; o razlichii mezhdu nimi smotri v sleduyushchem razdele.
Opisatel' funkcii podoben opisatelyu dlya funkcii, vozvrashchayu-
shchej ..., za isklyucheniem togo, chto on perechislyaet formal'nye
parametry opredelyaemoj funkcii.
opisatel'_funkcii:
opisatel' (spisok_parametrov)
neob
spisok parametrov:
identifikator
identifikator, spisok_parametrov
Telo_funkcii imeet formu
telo_funkcii:
spisok_opisanij sostavnoj_operator
Identifikatory iz spiska parametrov mogut byt' opisany v
spiske opisanij. Lyuboj identifikator iz etogo spiska, tip
kotorogo ne ukazan, schitaetsya imeyushchim tip int. Edinstvennym
dopustimym zdes' specifikatorom klassa pamyati yavlyaetsya
register; esli takoj klass pamyati specificirovan, to v
nachale vypolneniya funkcii sootvetstvuyushchij fakticheskij para-
metr kopiruetsya, esli eto vozmozhno, v registr.
Vot prostoj primer polnogo opredeleniya funkcii:
-39-
int max(a, b, c)
int a, b, c;
{
int m;
m = (a>b) ? a:b;
return((m>c) ? m:c);
}
Zdes' int - specifikator-tipa, mah(a,b,c) -
opisatel'_funkcii, int a,b,c; - spisok-opisanij formal'nyh
parametrov, { ... } - blok, soderzhashchij tekst operatora.
V yazyke Si vse fakticheskie parametry tipa float preob-
razuyutsya k tipu double, tak chto opisaniya formal'nyh paramet-
rov, ob座avlennyh kak float, mogut rabotat' s parametrami
tipa double. Analogichno, poskol'ku ssylka na massiv v lyubom
kontekste (v chastnosti v fakticheskom parametre) rassmatriva-
etsya kak ukazatel' na pervyj element massiva, opisaniya for-
mal'nyh parametrov vida massiv ... mogut rabotat' s fakti-
cheskimi parametrami tipa ukazatel' na ... I nakonec, pos-
kol'ku funkcii ne mogut byt' peredany funkcii, bessmyslenno
opisyvat' formal'nyj parametr kak funkciyu (ukazateli na
takie ob容kty, konechno, dopuskayutsya).
PRIMECHANIE
V nekotoryh versiyah yazyka Si, v chastnosti, v versiyah
dlya mikroprocessorov, mozhet byt' zapreshchena peredacha
struktur i ob容dinenij cherez parametry funkcii.
7.2. Vneshnie opredeleniya dannyh
Vneshnee opredelenie dannyh imeet formu:
opredelenie_dannyh:
opisanie
Klassom pamyati takih dannyh mozhet byt' extern (v chastnosti,
po umolchaniyu) ili static, no ne auto ili register.
* 8. OBLASTX DEJSTVIYA IDENTIFIKATOROV
Vsya Si-programma ne obyazatel'no kompiliruetsya odnovre-
menno; ishodnyj tekst programmy mozhet hranit'sya v neskol'kih
fajlah i ranee skompilirovannye procedury mogut zagruzhat'sya
iz bibliotek. Svyaz' mezhdu funkciyami mozhet osushchestvlyat'sya kak
cherez yavnye obrashcheniya, tak i v rezul'tate raboty redaktora
svyazej.
Poetomu sleduet rassmotret' dva vida oblastej dejstviya:
vo pervyh, tu, kotoraya mozhet byt' nazvana leksicheskoj
oblast'yu dejstviya identifikatora i kotoraya po sushchestvu
yavlyaetsya toj oblast'yu v programme, gde etot identifikator
-40-
mozhno ispol'zovat', ne vyzyvaya diagnosticheskogo soobshcheniya
"neopredelennyj identifikator"; i vo-vtoryh, oblast' dejst-
viya, kotoraya svyazana s vneshnimi identifikatorami i kotoraya
harakterizuetsya pravilom, chto ssylki na odin i tot zhe vnesh-
nij identifikator yavlyayutsya ssylkami na odin i tot zhe ob容kt.
8.1. Leksicheskaya oblast' dejstviya
Leksicheskaya oblast' dejstviya identifikatorov, opisannyh
vo vneshnih opredeleniyah, prostiraetsya ot opredeleniya do
konca ishodnogo fajla, v kotorom on nahoditsya. Leksicheskaya
oblast' dejstviya identifikatorov, yavlyayushchihsya formal'nymi
parametrami, rasprostranyaetsya na tu funkciyu, k kotoroj oni
otnosyatsya. Leksicheskaya oblast' dejstviya identifikatorov,
opisannyh v nachale bloka, prostiraetsya do konca etogo bloka.
Leksicheskoj oblast'yu dejstviya metok yavlyaetsya ta funkciya, v
kotoroj oni nahodyatsya.
Poskol'ku vse ssylki na odin i tot zhe vneshnij identifi-
kator otnosyatsya k odnomu i tomu zhe ob容ktu, kompilyator pro-
veryaet vse opisaniya odnogo i togo zhe vneshnego identifikatora
na sovmestimost'; v dejstvitel'nosti ih oblast' dejstviya
rasprostranyaetsya na ves' fajl, v kotorom oni nahodyatsya.
Vo vseh sluchayah, odnako, esli nekotoryj identifikator
yavnym obrazom opisan v nachale bloka, vklyuchaya i blok, kotoryj
obrazuet funkciyu, to dejstvie lyubogo opisaniya etogo identi-
fikatora vne bloka priostanavlivaetsya do konca etogo bloka.
Napomnim takzhe, chto identifikatory, sootvetstvuyushchie
obychnym peremennym, s odnoj storony, i identifikatory, soot-
vetstvuyushchie chlenam i yarlykam struktur i ob容dinenij, s dru-
goj storony, formiruyut dva neperesekayushchihsya klassa, kotorye
ne vstupayut v protivorechie. CHleny i yarlyki struktur podchinya-
yutsya tem zhe samym pravilam opredeleniya oblastej dejstviya,
kak i drugie identifikatory. Imena, specificiruemye s
pomoshch'yu typedef, vhodyat v tot zhe klass, chto i obychnye iden-
tifikatory. Oni mogut byt' pereopredeleny vo vnutrennih
blokah, no vo vnutrennem opisanii tip dolzhen byt' ukazan
yavno:
typedef float distance;
...
{
auto int distance;
...
Vo vtorom opisanii specifikator tipa int dolzhen prisutstvo-
vat', tak kak v protivnom sluchae eto opisanie budet prinyato
za opisanie bez opisatelej s tipom distance.
-41-
8.2. Oblast' dejstviya vneshnih identifikatorov
Esli funkciya ssylaetsya na identifikator, opisannyj kak
extern, to gde-to sredi fajlov ili bibliotek, obrazuyushchih
polnuyu programmu, dolzhno soderzhat'sya vneshnee opredelenie
etogo identifikatora. Vse funkcii dannoj programmy, kotorye
ssylayutsya na odin i tot zhe vneshnij identifikator, ssylayutsya
na odin i tot zhe ob容kt, tak chto sleduet pozabotit'sya, chtoby
specificirovannye v etom opredelenii tip i razmer byli sov-
mestimy s tipom i razmerom, ukazyvaemymi v kazhdoj funkcii,
kotoraya ssylaetsya na eti dannye.
Poyavlenie klyuchevogo slova extern vo vneshnem opredelenii
ukazyvaet na to, chto pamyat' dlya opisannyh v nem identifika-
torov budet vydelena v drugom fajle. Sledovatel'no, v sosto-
yashchej iz mnogih fajlov programme vneshnee opredelenie identi-
fikatora, ne soderzhashchee specifikatora extern, dolzhno poyav-
lyat'sya tol'ko v odnom iz etih fajlov. Lyubye drugie fajly,
kotorye zhelayut dat' vneshnee opredelenie etogo identifika-
tora, dolzhny vklyuchat' v eto opredelenie slovo extern. Iden-
tifikator mozhet byt' inicializirovan tol'ko v tom opisanii,
kotoroe privodit k vydeleniyu pamyati.
Iz etogo pravila v OS DEMOS imeetsya isklyuchenie. Vneshnij
ob容kt mozhet prisutstvovat' v neskol'kih opisaniyah bez
extern. Pri etom dlina ob容kta v raznyh opisaniyah dolzhna
sovpadat', a inicializaciya, esli ona est', dolzhna provo-
dit'sya rovno v odnom iz opisanij. Pri narushenii etih pravil
budet vydana oshibka na etape redaktirovanii svyazej prog-
rammy.
Identifikatory, vneshnee opredelenie kotoryh nachinaetsya
so slova static, nedostupny iz drugih fajlov. Funkcii mogut
byt' opisany kak static.
Ne vsegda neobhodimo specificirovat' i klass pamyati i
tip identifikatora v opisanii. Vo vneshnih opredeleniyah i
opisaniyah formal'nyh parametrov i chlenov struktur klass
pamyati opredelyaetsya po kontekstu. Esli v nahodyashchemsya vnutri
funkcii opisanii ne ukazan tip, a tol'ko klass pamyati, to
predpolagaetsya, chto identifikator imeet tip int; esli ne
ukazan klass pamyati, a tol'ko tip, to identifikator predpo-
lagaetsya opisannym kak auto. Isklyuchenie iz poslednego pra-
vila daetsya dlya funkcij, potomu chto specifikator auto dlya
funkcij yavlyaetsya bessmyslennym (yazyk Si ne v sostoyanii kom-
pilirovat' programmu v stek); esli identifikator imeet tip
funkciya, vozvrashchayushchaya ..., to on predpolagaetsya neyavno opi-
sannym kak extern.
Vhodyashchij v vyrazhenie i neopisannyj ranee identifikator,
za kotorym sleduet skobka (, schitaetsya opisannym po
-42-
kontekstu kak funkciya, vozvrashchayushchaya int.
/* extern */ int tab[100];
static /* int */ t1;
/* int */ func(i) /* int i; */
{ register /* int */ k;
/* auto */ char buf[512];
/* extern int f1(); */
... f1(a,b) ...
* 9. PREPROCESSOR YAZYKA 'SI'
Kompilyator yazyka Si soderzhit preprocessor, kotoryj poz-
volyaet osushchestvlyat' makropodstanovki, uslovnuyu kompilyaciyu i
vklyuchenie imenovannyh fajlov. Stroki, nachinayushchiesya s #,
yavlyayutsya komandami etogo preprocessora. Sintaksis etih strok
ne svyazan s ostal'nym yazykom; oni mogut poyavlyat'sya v lyubom
meste i ih vliyanie rasprostranyaetsya (nezavisimo ot oblasti
dejstviya) do konca ishodnogo programmnogo fajla. Fakticheski
preprocessor rasshiryaet vozmozhnosti yazyka Si, realizuya takie
funkcii, kotorye v drugih yazykah vhodyat v sostav samogo
yazyka (naprimer, parametricheskie konstanty v Fortrane-77).
Komanda
#define identifikator stroka_leksem
(obratite vnimanie na otsutstvie v konce tochki s zapyatoj)
privodit k tomu, chto preprocessor zamenyaet posleduyushchie vhozh-
deniya etogo identifikatora na ukazannuyu stroku leksem.
Stroka vida
#define identifikator(identifika-
tor,...,identifikator) stroka_leksem
gde mezhdu pervym identifikatorom i otkryvayushchejsya skobkoj "("
net probela, predstavlyaet soboj makroopredelenie s argumen-
tami. V dal'nejshem pervyj identifikator, za kotorym sleduet
otkryvayushchaya skobka "(", posledovatel'nost' razdelennyh zapya-
tymi leksem i zakryvayushchaya skobka ")", zamenyayutsya strokoj
leksem iz opredeleniya. Kazhdoe vhozhdenie identifikatora, upo-
myanutogo v spiske formal'nyh parametrov v opredelenii, zame-
nyaetsya sootvetstvuyushchej strokoj leksem iz obrashcheniya. Fakti-
cheskimi argumentami v obrashchenii yavlyayutsya stroki leksem, raz-
delennye zapyatymi; odnako zapyatye, vhodyashchie v zakavychennye
stroki ili zaklyuchennye v kruglye skobki, ne razdelyayut argu-
mentov. Kolichestvo formal'nyh i fakticheskih parametrov
dolzhno sovpadat'. Tekst vnutri stroki ili simvol'noj kons-
tanty ne podlezhit zamene.
-43-
V oboih sluchayah zamenennaya stroka prosmatrivaetsya snova
s cel'yu obnaruzheniya drugih identifikatorov, izvestnyh prep-
rocessoru. V oboih sluchayah slishkom dlinnaya stroka opredele-
niya mozhet byt' prodolzhena na drugoj stroke, esli pomestit' v
konce prodolzhaemoj stroki obratnuyu kosuyu chertu "\".
Opisyvaemaya vozmozhnost' osobenno polezna dlya opredele-
niya "ob座avlyaemyh konstant", kak, naprimer,
#define TABSIZE 100
int table[TABSIZE];
ili dlya zameny nekotoryh funkcij s pomoshch'yu makropodstanovki:
#define max(a,b) ((a)>(b)?(a):(b))
x = max(y,20)
(v poslednem opredelenii a i b vzyaty v skobki, dlya togo,
chtoby fakticheskimi parametrami makro mogli by byt' proiz-
vol'nye vyrazheniya.
Komanda
#undef identifikator
privodit k otmene preprocessornogo opredeleniya dannogo iden-
tifikatora.
Opredelit' identifikator mozhno ne tol'ko s pomoshch'yu
komandy #define, no takzhe i pri vyzove kompilyatora, s
pomoshch'yu parametrov komandy cc.
Komanda
#include "filename"
privodit k zamene etoj stroki na vse soderzhimoe fajla s ime-
nem filename. Fajl s etim imenem snachala ishchetsya v tekushchem
spravochnike, a zatem v drugih "standartnyh" mestah, oprede-
lyaemyh pol'zovatelem pri vyzove kompilyatora. V otlichie ot
etogo komanda
#include <filename>
ishchet fajl tol'ko v standartnom spravochnike sistemy.
V OS DEMOS fajl ishchetsya v spravochnike /usr/include.
Komandy #include mogut byt' vlozhennymi.
-44-
9.3. Uslovnaya kompilyaciya
Komanda preprocessora
#if konstantnoe vyrazhenie
proveryaet, otlichno li ot nulya znachenie konstantnogo vyrazhe-
niya. Komanda:
#ifdef identifikator
proveryaet, opredelen li etot identifikator v nastoyashchij
moment v preprocessore, t.e. opredelen li etot identifikator
s pomoshch'yu komandy #define. Komanda:
#ifndef identifikator
proveryaet, yavlyaetsya li etot identifikator v dannyj moment ne
opredelennym dlya preprocessora.
Za kazhdym iz treh perechislennyh vidov strok mozhet sle-
dovat' proizvol'noe chislo strok, vozmozhno soderzhashchih komandu
preprocessora
#else
a zatem dolzhna sledovat' komanda:
#endif
Esli proveryaemoe uslovie istinno, to lyubye stroki mezhdu
#else i #endif ignoriruyutsya. Esli proveryaemoe uslovie lozhno,
to lyubye stroki mezhdu proveryaemoj strokoj i #else ili, pri
otsutstvii #else, #endif ignoriruyutsya.
|ti konstrukcii mogut byt' vlozhennymi.
Naprimer:
#ifdef DEBUG
fprintf(stderr,"i=%o j=%d\n",i,j);
#endif
Peremennaya preprocessora mozhet byt' opredelena ne tol'ko v
samoj programme, no i pri vyzove translyatora.
Dlya drugih preprocessorov, generiruyushchih Si-programmy,
polezna sleduyushchaya komanda:
#line konstanta "imya_fajla"
-45-
kotoraya soobshchaet kompilyatoru (dlya diagnosticheskih soobshche-
nij), chto sleduyushchaya stroka ishodnogo fajla imeet nomer,
zadavaemyj konstantoj, i chto tekushchij vhodnoj fajl imenuetsya
imenem_fajla. Esli imya_fajla otsutstvuet, to zapominaemoe
imya fajla ne izmenyaetsya. Primer:
#line 250 "gram.y"
* 10. DOPOLNITELXNAYA INFORMACIYA O TIPAH
V etom razdele obobshchayutsya svedeniya ob operaciyah, koto-
rye mozhno primenyat' tol'ko k ob容ktam opredelennyh tipov.
10.1. Struktury i ob容dineniya
So strukturami i ob容dineniyami mogut proizvodit'sya sle-
duyushchie operacii: ssylka na odin iz chlenov struktury ili
ob容dineniya (s pomoshch'yu operacii .), poluchenie adresa (s
pomoshch'yu unarnoj operacii &), prisvaivanie struktury struk-
ture, peredacha struktury v kachestve formal'nogo parametra,
vozvrat struktury funkciej. Vse ostal'nye operacii zapre-
shcheny.
V realizacii vozvrashcheniya struktur funkciyami na CM-|VM
imeetsya kovarnyj defekt: esli vo vremya vozvrata proishodit
preryvanie i ta zhe samaya funkciya reenterabel'no vyzyvaetsya
vo vremya etogo preryvaniya, to znachenie, vozvrashchaemoe iz per-
vogo vyzova, mozhet byt' isporcheno. |ta trudnost' mozhet voz-
niknut' tol'ko pri nalichii istinnogo preryvaniya, kak iz ope-
racionnoj sistemy, tak i iz programmy pol'zovatelya; preryva-
niya, kotoroe dejstvitel'no asinhronno; obychnye rekursivnye
vyzovy sovershenno bezopasny.
V razdele "Vyrazheniya" govoritsya, chto pri pryamoj ili
kosvennoj ssylke na strukturu (s pomoshch'yu . ili ->) imya
sprava dolzhno byt' chlenom konstrukcii, nazvannoj ili ukazan-
noj vyrazheniem sleva. |to ogranichenie ne navyazyvaetsya strogo
kompilyatorom, chtoby dat' vozmozhnost' obojti pravila soot-
vetstviya tipov. V dejstvitel'nosti pered . dopuskaetsya
lyuboe l_znachenie i zatem predpolagaetsya, chto eto l_znachenie
imeet formu struktury, dlya kotoroj stoyashchee sprava imya yavlya-
etsya chlenom. Takim zhe obrazom, ot vyrazheniya, stoyashchego pered
->, trebuetsya tol'ko byt' ukazatelem ili celym. V sluchae
ukazatelya predpolagaetsya, chto on ukazyvaet na strukturu, dlya
kotoroj stoyashchee sprava imya yavlyaetsya chlenom. V sluchae celogo
ono rassmatrivaetsya kak absolyutnyj adres sootvetstvuyushchej
struktury, zadannyj v edinicah mashinnoj pamyati.
Takie struktury ne yavlyayutsya perenosimymi.
-46-
Tol'ko dve operacii mozhno primenyat' k funkcii: vyzvat'
ee ili izvlech' ee adres. Esli imya funkcii vhodit v vyrazhenie
ne v pozicii imeni funkcii, sootvetstvuyushchej obrashcheniyu k nej,
to generiruetsya ukazatel' na etu funkciyu. Sledovatel'no,
chtoby peredat' odnu funkciyu drugoj, mozhno napisat'
int f();
...
g(f);
togda opredelenie funkcii g moglo by vyglyadet' tak:
g(funcp)
int (*funcp)();
{
...
(*funcp)();
...
}
Obratite vnimanie, chto v vyzyvayushchej procedure funkciya f
dolzhna byt' opisana yavno, potomu chto za ee poyavleniem v g(f)
ne sleduet skobka "(".
10.3. Massivy, ukazateli i indeksaciya
Kazhdyj raz, kogda identifikator, imeyushchij tip massiva,
poyavlyaetsya v vyrazhenii, on preobrazuetsya v ukazatel' na per-
vyj chlen etogo massiva. Iz-za etogo preobrazovaniya massivy
ne yavlyayutsya l_znacheniyami. Po opredeleniyu operaciya indeksacii
"[]" interpretiruetsya takim obrazom, chto e1[e2] schitaetsya
identichnym vyrazheniyu *((e1)+(e2)). Soglasno pravilam preob-
razovanij, primenyaemym pri operacii +, esli e1 - massiv, a
e2 - celoe, to e1[e2] ssylaetsya na e2-j chlen massiva e1.
Poetomu, nesmotrya na nesimmetrichnyj vid, operaciya indeksacii
yavlyaetsya kommutativnoj.
V sluchae mnogomernyh massivov primenyaetsya analogichnoe
pravilo. Esli e yavlyaetsya n-mernym massivom razmera
i*j*...*k, to pri poyavlenii v vyrazhenii e preobrazuetsya v
ukazatel' na (n-1)-mernyj massiv razmera j*...*k. Esli ope-
raciya * libo yavno, libo neyavno, kak rezul'tat indeksacii,
primenyaetsya k etomu ukazatelyu, to rezul'tatom operacii budet
ukazannyj (n-1)-mernyj massiv, kotoryj sam nemedlenno preob-
razuetsya v ukazatel'.
Rassmotrim, naprimer, opisanie:
int u[3][5];
Zdes' u - massiv celyh razmera 3*5. Pri poyavlenii v
-47-
vyrazhenii u preobrazuetsya v ukazatel' na pervyj iz treh mas-
sivov iz 5 celyh. V vyrazhenii u[i], kotoroe ekvivalentno
*(u+i), snachala u preobrazuetsya v ukazatel' tak, kak opisano
vyshe; zatem i preobrazuetsya k tipu u, chto vyzyvaet umnozhenie
i na dlinu ob容kta, na kotoryj ukazyvaet ukazatel', a imenno
na 5 celyh ob容ktov. Rezul'taty skladyvayutsya, i primenenie
kosvennoj adresacii daet massiv (iz 5 celyh), kotoryj v svoyu
ochered' preobrazuetsya v ukazatel' na pervoe iz etih celyh.
Esli v vyrazhenie vhodit i drugoj indeks, to ta zhe samaya
argumentaciya primenyaetsya snova; rezul'tatom na etot raz
budet celoe.
Iz vsego etogo sleduet, chto massivy v yazyke Si hranyatsya
postrochno (poslednij indeks izmenyaetsya bystree vsego) i chto
pervyj indeks v opisanii pomogaet opredelit' obshchee koli-
chestvo pamyati, trebuemoe dlya hraneniya massiva, no ne igraet
nikakoj drugoj roli v vychisleniyah, svyazannyh s indeksaciej.
10.4. YAvnye preobrazovaniya ukazatelej
Razreshayutsya opredelennye preobrazovaniya s ispol'zova-
niem ukazatelej. Oni imeyut nekotorye zavisyashchie ot konkret-
noj realizacii aspekty. Vse eti preobrazovaniya zadayutsya s
pomoshch'yu operacii yavnogo preobrazovaniya tipa.
Ukazatel' mozhet byt' preobrazovan v lyuboj iz celochis-
lennyh tipov, dostatochno bol'shoj dlya ego hraneniya. Trebuetsya
li pri etom int ili long, zavisit ot konkretnoj mashiny (v OS
DEMOS dlya SM |VM trebuetsya int). Preobrazuyushchaya funkciya
takzhe yavlyaetsya mashinno-zavisimoj, no ona budet vpolne
estestvennoj dlya teh, kto znaet strukturu adresacii v
mashine. Detali dlya nekotoryh konkretnyh mashin privodyatsya
nizhe.
Ob容kt celochislennogo tipa mozhet byt' yavnym obrazom
preobrazovan v ukazatel'. Takoe preobrazovanie vsegda pere-
vodit preobrazovannoe iz ukazatelya celoe v tot zhe samyj uka-
zatel', no v drugih sluchayah ono budet mashinno-zavisimym.
Ukazatel' na odin tip mozhet byt' preobrazovan v ukaza-
tel' na drugoj tip. Esli preobrazuemyj ukazatel' ne ukazy-
vaet na ob容kty, kotorye podhodyashchim obrazom vyravneny v
pamyati, to rezul'tiruyushchij ukazatel' mozhet pri ispol'zovanii
vyzyvat' oshibki adresacii. Garantiruetsya, chto ukazatel' na
ob容kt zadannogo razmera mozhet byt' preobrazovan v ukazatel'
na ob容kt men'shego razmera i snova obratno, ne preterpev pri
etom izmeneniya.
Naprimer, procedura raspredeleniya pamyati alloc mogla by
prinimat' zapros na razmer vydelyaemogo ob容kta v bajtah, a
vozvrashchat' ukazatel' na simvoly; eto mozhno bylo by ispol'zo-
vat' sleduyushchim obrazom.
-48-
extern char *alloc();
double *dp;
dp=(double*) alloc(sizeof(double));
*dp=22.0/7.0;
Funkciya alloc dolzhna obespechivat' (mashinno-zavisimym sposo-
bom), chto vozvrashchaemoe eyu znachenie budet podhodyashchim dlya pre-
obrazovaniya v ukazatel' na double; v takom sluchae ispol'zo-
vanie etoj funkcii budet perenosimym.
Predstavlenie ukazatelya na CM-|VM sootvetstvuet 16-
bitovomu celomu i izmeryaetsya v bajtah. Ob容kty tipa char ne
imeyut nikakih ogranichenij na vyravnivanie; vse ostal'nye
ob容kty dolzhny imet' chetnye adresa.
* 11. KONSTANTNYE VYRAZHENIYA
V neskol'kih mestah v yazyke Si trebuyutsya vyrazheniya,
kotorye posle vychisleniya stanovyatsya konstantami: posle vari-
antnogo prefiksa case, v kachestve granic massivov i v inici-
alizatorah. V pervyh dvuh sluchayah vyrazhenie mozhet soderzhat'
tol'ko celye konstanty, simvol'nye konstanty i vyrazheniya
sizeof, vozmozhno svyazannye libo binarnymi operaciyami
+ - * / . % & | ^ << >> == 1= <> <= >=
libo unarnymi operaciyami
- ~
libo ternarnoj operaciej
?:
Kruglye skobki mogut ispol'zovat'sya dlya gruppirovki, no ne
dlya obrashcheniya k funkciyam.
V sluchae inicializatorov dopuskaetsya bol'shaya (udarenie
na bukvu o) svoboda; krome perechislennyh vyshe konstantnyh
vyrazhenij mozhno takzhe primenyat' unarnuyu operaciyu & k vneshnim
ili staticheskim ob容ktam i k vneshnim ili staticheskim massi-
vam, imeyushchim v kachestve indeksov konstantnoe vyrazhenie.
Unarnaya operaciya & mozhet byt' takzhe primenena neyavno, v
rezul'tate poyavleniya neindeksirovannyh massivov i funkcij.
Osnovnoe pravilo zaklyuchaetsya v tom, chto posle vychisleniya
inicializator dolzhen stanovitsya libo konstantoj, libo adre-
som ranee opisannogo vneshnego ili staticheskogo ob容kta plyus
ili minus konstanta.
* 12. SOOBRAZHENIYA O PERENOSIMOSTI
Odnim iz dostoinstv yazyka Si schitaetsya perenosimost'
programm na Si, kotoraya svyazana kak s otnositel'noj mashinnoj
-49-
nezavisimost'yu samogo yazyka, tak i s sovmestimost'yu sredy,
obespechivaemoj sovmestimymi s OS UNIX operacionnymi siste-
mami. Vmeste s tem, pri napisanii na yazyke Si takih prog-
ramm, kotorye ne dolzhny zaviset' ot konkretnoj |VM, neobho-
dimo uchityvat' to, chto nekotorye chasti yazyka Si po svoej
suti mashinno-zavisimy. Sleduyushchee nizhe perechislenie potenci-
al'nyh trudnostej hotya i ne yavlyayutsya vseob容mlyushchimi, no
vydelyaet osnovnye iz nih.
Voprosy, celikom svyazannye s apparatnym oborudovaniem,
takie kak razmer slova, svojstva veshchestvennoj arifmetiki i
celogo deleniya, ne predstavlyayut osobennyh zatrudnenij. Dru-
gie aspekty apparatnyh sredstv nahodyat svoe otrazhenie v raz-
lichnyh realizaciyah. Nekotorye iz nih, v chastnosti, znakovoe
rasshirenie (preobrazuyushchee otricatel'nyj simvol v otricatel'-
noe celoe) i poryadok, v kotorom pomeshchayutsya bajty v slove,
predstavlyayut soboj nepriyatnost', kotoraya dolzhna tshchatel'no
otslezhivat'sya. Bol'shinstvo ostal'nyh problem etogo tipa ne
vyzyvaet skol'ko_nibud' znachitel'nyh zatrudnenij.
CHislo peremennyh tipa register, kotoroe fakticheski
mozhet byt' pomeshcheno v registry, menyaetsya ot mashiny k mashine,
takzhe kak i nabor dopustimyh dlya nih tipov. Tem ne menee vse
kompilyatory na svoih mashinah rabotayut nadlezhashchim obrazom;
lishnie ili nedopustimye registrovye opisaniya ignoriruyutsya.
Nekotorye trudnosti voznikayut tol'ko pri ispol'zovanii
somnitel'noj praktiki programmirovaniya, ili pri ispol'zova-
nii osobennostej konkretnoj realizacii. Pisat' programmy,
kotorye zavisyat ot takih osobennostej, chrezvychajno nera-
zumno.
YAzykom ne ukazyvaetsya poryadok vychisleniya argumentov
funkcij; oni vychislyayutsya sprava nalevo na CM-|VM i |VM PDP-
11 i VAXR-11 firmy DEC i sleva napravo na bol'shinstve
ostal'nyh mashin. Poryadok, v kotorom proishodyat pobochnye
effekty, takzhe ne specificiruetsya.
Tak kak simvol'nye konstanty v dejstvitel'nosti yavlya-
yutsya ob容ktami tipa int, dopuskaetsya ispol'zovanie simvol'-
nyh konstant, sostoyashchih iz neskol'kih simvolov. Odnako, pos-
kol'ku poryadok, v kotorom simvoly pripisyvayutsya k slovu,
menyaetsya ot mashiny k mashine, konkretnaya realizaciya okazyva-
etsya ves'ma mashinno_zavisimoj.
Poryadok prisvaivaniya polej k slovam i simvolov k celym
takzhe zavisit ot |VM. Takie razlichiya nezametny dlya izoliro-
vannyh programm, v kotoryh ne razresheno smeshivat' tipy (pre-
obrazuya, naprimer, ukazatel' na int v ukazatel' na char i
zatem proveryaya ukazyvaemuyu pamyat'), no dolzhny uchityvat'sya
pri soglasovanii s nakladyvaemymi izvne shemami pamyati.
-50-
YAzyk, prinyatyj na razlichnyh kompilyatorah, otlichaetsya
tol'ko neznachitel'nymi detalyami. Samoe zametnoe otlichie sos-
toit v tom, chto ispol'zuemyj v nastoyashchee vremya kompilyator na
CM-|VM ne inicializiruet struktury, kotorye soderzhat polya
bitov, ne imeet tipa "unsigned char" i imeet nekotorye ogra-
nicheniya na operacii prisvaivaniya v opredelennyh kontekstah,
svyazannyh s ispol'zovaniem znacheniya prisvaivaniya struktur.
V staryh programmah mozhno vstretit' nekotorye ustarev-
shie konstrukcii. Hotya bol'shinstvo versij kompilyatora podder-
zhivaet takie anahronizmy, oni v konce koncov ischeznut, osta-
viv za soboj tol'ko problemy perenosimosti.
V rannih versiyah Si dlya problem prisvaivaniya ispol'zo-
valas' forma =op, a ne op=, privodya k dvusmyslennostyam,
tipichnym primerom kotoryh yavlyaetsya
h =-1
gde h fakticheski umen'shaetsya, poskol'ku operacii = i - pri-
mykayut drug k drugu, no chto vpolne moglo rassmatrivat'sya i
kak prisvaivanie -1 k h.
Sintaksis inicializatorov izmenilsya: ran'she znak
ravenstva, s kotorogo nachinaetsya inicializator, otsutstvo-
val, tak chto vmesto
int h = 1;
ispol'zovalos'
int h 1;
izmenenie bylo vneseno iz_za inicializacii
int f (1+2)
kotoraya dostatochno sil'no napominaet opredelenie funkcii,
chtoby smutit' kompilyatory.
* 13. STANDARTNAYA BIBLIOTEKA VVODA I VYVODA
Sredstva vvoda/vyvoda ne yavlyayutsya sostavnoj chast'yu
yazyka Si. V etoj glave budet opisana "standartnaya biblio-
teka vvoda/vyvoda", to est' nabor funkcij, razrabotannyh dlya
obespecheniya standartnoj sistemy vvoda/vyvoda dlya Si- prog-
ramm. |ti funkcii otrazhayut tol'ko te operacii, kotorye mogut
byt' obespecheny na bol'shinstve sovremennyh operacionnyh sis-
tem. Procedury dostatochno effektivny dlya togo, chtoby pol'zo-
vateli redko chuvstvovali neobhodimost' obojti ih "radi
-51-
effektivnosti", kak by ni byla vazhna konkretnaya zadacha. I
nakonec, eti procedury byli zadumany avtorami yazyka "pereno-
simymi" v tom smysle, chto oni dolzhny sushchestvovat' v sovmes-
timom vide na lyuboj sisteme, gde imeetsya yazyk Si, i chto
programmy, kotorye ogranichivayut svoi vzaimodejstviya s sis-
temnymi vozmozhnostyami, predostavlyaemymi standartnoj biblio-
tekoj, mozhno budet perenosit' s odnoj sistemy na druguyu po
sushchestvu bez izmenenij.
Dalee opisyvayutsya osnovnye principy organizacii
vvoda/vyvoda v programmah na yazyke Si, ispol'zuyushchih biblio-
teku vvoda/vyvoda. Polnoe opisanie etoj biblioteki imeetsya v
rukovodstve programmista (chast' 4) ili v operativnoj doku-
mentacii ("man(3)"). Programmy, rabotayushchie v OS DEMOS,
mogut takzhe obrashchat'sya k funkciyam vvoda/vyvoda nizkogo
urovnya, kotorye realizovany neposredstvenno v yadre OS DEMOS,
no takaya neobhodimost' voznikaet dostatochno redko.
13.1. Obrashchenie k standartnoj biblioteke
Kazhdyj ishodnyj fajl, kotoryj obrashchaetsya k funkcii iz
standartnoj biblioteki, dolzhen gde to v nachale soderzhat'
stroku
#include <stdio.h>
V fajle stdio.h opredelyayutsya nekotorye makrosy i peremennye,
ispol'zuemye bibliotekoj vvoda/vyvoda.
13.2. Standartnyj vvod i vyvod
Samyj prostoj mehanizm vvoda zaklyuchaetsya v chtenii po
odnomu simvolu za raz iz "standartnogo vvoda" (obychno s ter-
minala pol'zovatelya) s pomoshch'yu funkcii getchar. Funkciya
getchar() celogo tipa pri kazhdom k nej obrashchenii vozvrashchaet
sleduyushchij vvodimyj simvol. V bol'shinstve sistem, kotorye
podderzhivayut yazyk Si, terminal mozhet byt' zamenen nekotorym
fajlom s pomoshch'yu oboznacheniya "<". Esli nekotoraya programma
prog ispol'zuet funkciyu getchar, to komandnaya stroka
prog <infile
privedet k tomu, chto prog budet chitat' iz fajla infile, a ne
s terminala. Pereklyuchenie vvoda delaetsya takim obrazom, chto
sama programma prog ne zamechaet izmeneniya; v chastnosti
stroka "<infile" ne vklyuchaetsya v komandnuyu stroku argumentov
(sm. sleduyushchuyu glavu). Pereklyuchenie vvoda okazyvaetsya neza-
metnym i v tom sluchae, kogda vyvod postupaet iz drugoj prog-
rammy cherez mezhprocessnyj kanal. Naprimer, komandnaya stroka
otherprog | prog
progonyaet dve programmy, otherprog i prog, tak, chto
-52-
standartnym vvodom dlya prog sluzhit standartnyj vyvod other-
prog.
Funkciya getchar vozvrashchaet znachenie EOF, kogda dostiga-
etsya konec fajla, kakoj by vvod ona pri etom ne schityvala.
Standartnaya biblioteka polagaet simvolicheskuyu konstantu EOF
ravnoj -1 (posredstvom #define v fajle stdio.h), no proverki
sleduet pisat' v terminah EOF, a ne -1, chtoby izbezhat' zavi-
simosti ot konkretnogo znacheniya.
Vyvod mozhno osushchestvlyat' s pomoshch'yu funkcii putchar(c),
pomeshchayushchej simvol 'c' v "standartnyj vyvod", kotoryj po
umolchaniyu yavlyaetsya terminalom. Vyvod mozhno pri vyzove prog-
rammy napravit' v nekotoryj fajl s pomoshch'yu oboznacheniya ">".
Esli prog ispol'zuet putchar, to komandnaya stroka
prog > outfile
privedet k zapisi standartnogo vyvoda v fajl outfile, a ne
na terminal. V sisteme DEMOS mozhno takzhe ispol'zovat' mezhp-
rocessnyj kanal.
V standartnoj biblioteke vvoda/vyvoda "funkcii" getchar
i putchar na samom dele mogut byt' makrosami. |to pozvolyaet
izbezhat' nakladnyh rashodov na obrashchenie k funkcii dlya obra-
botki kazhdogo simvola.
13.3. Formatnyj vyvod - funkciya printf
Dve funkcii: printf dlya vyvoda i scanf dlya vvoda (sle-
duyushchij razdel) pozvolyayut preobrazovyvat' chislennye velichiny
v simvol'noe predstavlenie i obratno. Oni takzhe pozvolyayut
generirovat' i interpretirovat' formatnye stroki. Funkciya
printf(control, arg1, arg2, ...)
preobrazuet argumenty v tekstovuyu formu v sootvetstvii s
formatami, zadannymi v upravlyayushchej stroke control, i vydaet
rezul'tat v standartnyj vyvod. Upravlyayushchaya stroka soderzhit
dva tipa ob容ktov: obychnye simvoly, kotorye prosto kopiru-
yutsya v vyhodnoj potok, i specifikacii preobrazovanij, kazhdaya
iz kotoryh vyzyvaet preobrazovanie i pechat' ocherednogo argu-
menta printf.
Kazhdaya specifikaciya preobrazovaniya nachinaetsya s simvola
"%" i zakanchivaetsya simvolom preobrazovaniya (bukvoj, oprede-
lyayushchej tip preobrazovaniya). Mezhdu "%" i simvolom preobrazo-
vaniya mogut nahodit'sya:
- Znak minus, kotoryj vyzyvaet vyravnivanie preobrazo-
vannogo argumenta po levomu krayu polya.
-53-
- Stroka cifr, zadayushchaya minimal'nuyu shirinu polya. Preob-
razovannoe chislo budet napechatano v pole po krajnej
mere etoj shiriny, a esli neobhodimo, to i v bolee
shirokom. Esli preobrazovannyj argument imeet men'she
simvolov, chem ukazannaya shirina polya, to on budet
dopolnen sleva (ili sprava, esli bylo ukazano vyrav-
nivanie po levomu krayu) zapolnyayushchimi simvolami do
etoj shiriny. Zapolnyayushchim simvolom obychno yavlyaetsya
probel, a esli shirina polya ukazyvaetsya s lidiruyushchim
nulem, to etim simvolom budet nul' (lidiruyushchij nul' v
dannom sluchae ne oznachaet vos'merichnoj shiriny polya).
- Tochka, kotoraya otdelyaet shirinu polya ot sleduyushchej
stroki cifr.
- Stroka cifr (tochnost'); ukazyvaet maksimal'noe chislo
simvolov stroki, kotorye dolzhny byt' napechatany, ili
chislo pechataemyh sprava ot desyatichnoj tochki cifr dlya
peremennyh tipa float ili double.
- Modifikator dliny l, kotoryj ukazyvaet, chto soot-
vetstvuyushchij element dannyh imeet tip long, a ne int.
Nizhe privodyatsya simvoly preobrazovaniya i ih smysl:
d - argument preobrazuetsya k desyatichnomu vidu;
o - argument preobrazuetsya v bezznakovuyu vos'merichnuyu
formu (bez lidiruyushchego nulya);
x - argument preobrazuetsya v bezznakovuyu shestnadcaterich-
nuyu formu (bez lidiruyushchih 0h);
u - argument preobrazuetsya v bezznakovuyu desyatichnuyu
formu;
c - argument rassmatrivaetsya kak otdel'nyj simvol;
s - argument yavlyaetsya strokoj: simvoly stroki pechatayutsya
do teh por, poka ne budet dostignut nulevoj simvol
ili ne budet napechatano kolichestvo simvolov, ukazan-
noe v specifikacii tochnosti;
e - argument, rassmatrivaemyj kak peremennaya tipa float
ili double, preobrazuetsya v desyatichnuyu formu v vide
[-]m.nnnnnne[+-]hh, gde dlina stroki iz n opredelya-
etsya ukazannoj tochnost'yu. Tochnost' po umolchaniyu ravna
6;
f - argument, rassmatrivaemyj kak peremennaya tipa float
ili double, preobrazuetsya v desyatichnuyu formu v vide
[-]mmm.nnnnn, gde dlina stroki iz n opredelyaetsya uka-
zannoj tochnost'yu. Tochnost' po umolchaniyu ravna 6.
-54-
Otmetim, chto eta tochnost' ne opredelyaet kolichestvo
pechataemyh v formate f znachashchih cifr;
g - ispol'zuetsya ili format %e ili %f, kakoj koroche; nez-
nachashchie nuli ne pechatayutsya.
Vmesto "ld"mozhno ispol'zovat' "D", vmesto "lo" - "O", vmesto
"lx" - "X".
Esli idushchij za % simvol ne yavlyaetsya simvolom preobrazo-
vaniya, to pechataetsya sam etot simvol; sledovatel'no,simvol %
mozhno napechatat', ukazav %%.
Bol'shinstvo iz formatnyh preobrazovanij ochevidno.
Edinstvennym isklyucheniem yavlyaetsya to, kak tochnost' vzaimo-
dejstvuet so strokami. Sleduyushchaya tablica demonstriruet vliya-
nie razlichnyh specifikacij na pechat' "hello, world" (12 sim-
volov). Vokrug kazhdogo polya pomeshcheny dvoetochiya dlya togo,
chtoby mozhno bylo opredelit' ego protyazhennost'.
:%10s: :hello, world:
:%10-s: :hello, world:
:%20s: : hello, world:
:%-20s: :hello, world :
:%20.10s: : hello, wor:
:%-20.10s: :hello, wor :
:%.10s: :hello, wor:
PREDOSTEREZHENIE: printf ispol'zuet svoj pervyj argument dlya
opredeleniya chisla posleduyushchih argumentov i ih tipov. Esli
kolichestvo argumentov okazhetsya nedostatochnym ili oni budut
imet' nesootvetstvuyushchie tipy, to vozniknet putanica i
rezul'taty budut nevernymi.
13.4. Formatnyj vvod - funkciya scanf
Osushchestvlyayushchaya vvod funkciya scanf yavlyaetsya analogom
printf i pozvolyaet provodit' v obratnom napravlenii mnogie
iz teh zhe samyh preobrazovanij. Funkciya
scanf(control, arg1, arg2, ...)
chitaet simvoly iz standartnogo vvoda, interpretiruet ih v
sootvetstvii s formatom, ukazannom v argumente control, i
pomeshchaet rezul'taty v ostal'nye argumenty. Upravlyayushchaya
stroka opisyvaetsya nizhe; drugie argumenty, kazhdyj iz kotoryh
dolzhen byt' ukazatelem, opredelyayut, kuda sleduet pomestit'
sootvetstvuyushchim obrazom preobrazovannyj vvod.
Upravlyayushchaya stroka obychno soderzhit specifikacii preob-
razovaniya, kotorye ispol'zuyutsya dlya neposredstvennoj interp-
retacii vhodnyh posledovatel'nostej. Upravlyayushchaya stroka
-55-
mozhet soderzhat':
- probely, tabulyacii ili simvoly novoj stroki ("simvoly
pustyh promezhutkov"), kotorye ignoriruyutsya;
- obychnye simvoly (ne %), kotorye predpolagayutsya sovpa-
dayushchimi so sleduyushchimi otlichnymi ot "simvolov pustyh
promezhutkov" simvolami vhodnogo potoka;
- specifikacii preobrazovaniya, sostoyashchie iz simvola %,
neobyazatel'nogo simvola podavleniya prisvaivaniya *,
neobyazatel'nogo chisla, zadayushchego maksimal'nuyu shirinu
polya i simvola preobrazovaniya.
Specifikaciya preobrazovaniya upravlyaet preobrazovaniem
sleduyushchego polya vvoda. Obychno rezul'tat pomeshchaetsya v pere-
mennuyu, kotoraya ukazyvaetsya sootvetstvuyushchim argumentom.
Esli, odnako , s pomoshch'yu simvola * ukazano podavlenie pris-
vaivaniya, to eto pole vvoda prosto propuskaetsya i nikakogo
prisvaivaniya ne proizvoditsya. Pole vvoda opredelyaetsya kak
stroka simvolov, kotorye otlichny ot "simvolov prostyh prome-
zhutkov"; ono prodolzhaetsya libo do sleduyushchego simvola pustogo
promezhutka, libo poka ne budet ischerpana shirina polya, esli
ona ukazana. Otsyuda sleduet, chto pri poiske nuzhnogo ej
vvoda, funkciya scanf budet peresekat' granicy strok, pos-
kol'ku simvol novoj stroki yavlyaetsya odnim iz simvolov pustyh
promezhutkov.
Imeetsya vozmozhnost' zadaniya bolee slozhnogo algoritma
vydeleniya polej vvoda, kotoraya opisana v rukovodstve prog-
rammista ("scanf(3)").
Simvol preobrazovaniya opredelyaet interpretaciyu polya
vvoda; poskol'ku v Si argumenty peredayutsya po znacheniyu,
argumenty scanf dolzhny byt' ukazatelyami. Dopuskayutsya sleduyu-
shchie simvoly preobrazovaniya:
d - Na vvode ozhidaetsya desyatichnoe celoe; sootvetstvuyushchij
argument dolzhen byt' ukazatelem na celoe.
o - Na vvode ozhidaetsya vos'merichnoe celoe (s lidiruyushchim
nulem ili bez nego); sootvetstvuyushchij argument dolzhen
byt' ukazatelem na celoe.
x - Na vvode ozhidaetsya shestnadcatirichnoe celoe (s lidiru-
yushchimi 0h ili bez nih); sootvetstvuyushchij argument dol-
zhen byt' ukazatelem na celoe.
h - Na vvode ozhidaetsya celoe tipa short; sootvetstvuyushchij
argument dolzhen byt' ukazatelem na celoe tipa short.
c - Ozhidaetsya otdel'nyj simvol; sootvetstvuyushchij argument
dolzhen byt' ukazatelem na simvoly; sleduyushchij vvodimyj
-56-
simvol pomeshchaetsya v ukazannoe mesto. Obychnyj propusk
simvolov pustyh promezhutkov v etom sluchae podavlya-
etsya; dlya chteniya sleduyushchego simvola, kotoryj ne yavlya-
etsya simvolom pustogo promezhutka, pol'zujtes' speci-
fikaciej preobrazovaniya %1s.
s - Ozhidaetsya simvol'naya stroka; sootvetstvuyushchij argument
dolzhen byt' ukazatelem simvolov, kotoryj ukazyvaet na
massiv simvolov, dostatochno bol'shoj dlya prinyatiya
stroki i dobavlyaemogo v konce simvola \0.
f - Ozhidaetsya chislo s veshchestvennoj tochkoj; sootvetstvuyu-
shchij argument dolzhen byt' ukazatelem na peremennuyu
tipa float.
e - Simvol preobrazovaniya e yavlyaetsya sinonimom dlya f.
Format vvoda peremennoj tipa float vklyuchaet neobyaza-
tel'nyj znak, stroku cifr, vozmozhno soderzhashchuyu desya-
tichnuyu tochku i neobyazatel'noe pole eksponenty, sosto-
yashchee iz bukvy e, za kotoroj sleduet celoe, vozmozhno
imeyushchee znak.
Pered simvolami preobrazovaniya d, o i x mozhet stoyat'
bukva l, kotoraya oznachaet, chto v spiske argumentov dolzhen
nahodit'sya ukazatel' na peremennuyu tipa long, a ne tipa int.
Analogichno, bukva l mozhet stoyat' pered simvolami preobrazo-
vaniya e ili f, govorya o tom, chto v spiske argumentov dolzhen
nahodit'sya ukazatel' na peremennuyu tipa double, a ne tipa
float.
Naprimer, obrashchenie
int 1;
float h;
char name[50];
scanf("%d %f %s", &i, &h, name);
so strokoj na vvode
25 54.32e-1 thompson
privodit k prisvaivaniyu i znacheniya 25, h - znacheniya 5.432 i
name - stroki "thompson", nadlezhashchim obrazom zakonchennoj
simvolom \0. |ti tri polya vvoda mozhno razdelit' proizvol'-
nym chislom probelov, tabulyacij i simvolov novoj stroki,
skol'ko vy pozhelaete. Obrashchenie
int i;
float h;
char name[50];
scanf("%2d %f %*d %2s", &i, &h, name);
s vvodom
-57-
56789 0123 45a72
prisvoit i znachenie 56, h - 789.0, propustit 0123 i pomestit
v name stroku "45". Pri sleduyushchem obrashchenii k lyuboj proce-
dure vvoda rassmotrenie nachnetsya s bukvy a. V etih dvuh pri-
merah name yavlyaetsya ukazatelem i, sledovatel'no, pered nim
ne nuzhno pomeshchat' znak &.
V kachestve drugogo primera privedem programmu dlya sum-
mirovaniya chisel, vvodimyh s terminala:
#include <stdio.h>
main() /* Primitivnyj kal'kulyator */
{
double sum, v;
sum =0;
while (scanf("%lf", &v) !=EOF)
printf("\t%.2fFI\n", sum += v);
}
Vypolnenie funkcii scanf zakanchivaetsya libo togda, kogda ona
ischerpyvaet svoyu upravlyayushchuyu stroku, libo kogda nekotoryj
element vvoda ne sootvetstvuet ocherednoj specifikacii preob-
razovaniya. V kachestve svoego znacheniya ona vozvrashchaet chislo
pravil'no raspoznannyh elementov vvoda. |to chislo mozhet byt'
ispol'zovano dlya opredeleniya kolichestva najdennyh elementov
vvoda. Pri vyhode na konec fajla vozvrashchaetsya EOF; podcherk-
nem, chto eto znachenie otlichno ot 0, oznachayushchego, chto sleduyu-
shchij vvodimyj simvol ne udovletvoryaet pervoj specifikacii v
upravlyayushchej stroke. Pri sleduyushchem obrashchenii k scanf poisk
vozobnovlyaetsya neposredstvenno za poslednim vvedennym simvo-
lom.
PREDOSTEREZHENIE: argumenty funkcii scanf dolzhny byt'
ukazatelyami. Nesomnenno, naibolee rasprostranennaya oshibka
sostoit v napisanii
scanf("%d", n);
vmesto
scanf("%d", &n);
13.5. Formatnoe preobrazovanie v pamyati
Ot funkcii scanf i printf proishodyat funkcii sscanf i
sprintf, kotorye osushchestvlyayut analogichnye preobrazovaniya, no
operiruyut so strokoj, a ne s fajlom. Obrashcheniya k etim funk-
ciyam imeyut vid:
-58-
sprintf(string, control, arg1, arg2, ...)
sscanf(string, control, arg1, arg2, ...)
Kak i ran'she , funkciya sprintf preobrazuet svoi argumenty
arg1, arg2 i t.d. v sootvetstvii s formatom, ukazannym v
control, no pomeshchaet rezul'taty v string, a ne v standartnyj
vyvod. Konechno, stroka string dolzhna byt' dostatochno velika,
chtoby prinyat' rezul'tat. Naprimer, esli name - eto simvol'-
nyj massiv, a n - celoe, to
sprintf(name, "temp%d", n);
sozdaet v name stroku vida "tempnnn", gde nnn - znachenie n.
Funkciya sscanf vypolnyaet obratnye preobrazovaniya - ona
prosmatrivaet stroku string v sootvetstvii s formatom v
argumente control i pomeshchaet rezul'tiruyushchie znacheniya v argu-
menty arg1, arg2 i t.d. |ti argumenty dolzhny byt' ukazate-
lyami. V rezul'tate obrashcheniya
sscanf(name, "temp%d", &n);
peremennaya n poluchaet znachenie stroki cifr, sleduyushchih za
temp v name.
Opisannye v nachale dannogo razdela programmy chitayut iz
standartnogo vvoda i pishut v standartnyj vyvod, kotorye pre-
dostavlyayutsya programme operacionnoj sistemoj.
Dlya programm, kotorye sami dolzhny organizovyvat' svyaz'
s fajlami, v biblioteke vvoda/vyvoda dejstvuyut sleduyushchie
pravila.
Prezhde chem schityvat' iz nekotorogo fajla ili zapisy-
vat' v nego, etot fajl dolzhen byt' otkryt s pomoshch'yu funkcii
open iz standartnoj biblioteki. Funkciya fopen beret vneshnee
imya (podobnoe h.c ili "temp002") i vozvrashchaet vnutrennee
imya, kotoroe dolzhno ispol'zovat'sya pri posleduyushchih chteniyah
iz fajla ili zapisyah v nego.
|to vnutrennee imya, nazyvaemoe "ukazatelem fajla", fak-
ticheski yavlyaetsya ukazatelem struktury, kotoraya soderzhit
informaciyu o fajle, takuyu kak mesto razmeshcheniya bufera, teku-
shchaya poziciya simvola v bufere, proishodit li chtenie iz fajla
ili zapis' v nego i tomu podobnoe. Pol'zovateli ne obyazany
znat' eti detali, potomu chto sredi opredelenij, poluchaemyh
iz fajla stdio.h, soderzhitsya opredelenie etoj struktury.
Edinstvennoe neobhodimoe dlya ukazatelya fajla opisanie
demonstriruetsya primerom: FILE *fp;
-59-
Zdes' govoritsya, chto fp yavlyaetsya ukazatelem na FILE.
Obratite vnimanie, chto file yavlyaetsya imenem tipa, podobnym
int, a ne yarlykom struktury; eto realizovano cherez
"#define".
Obrashchenie k funkcii fopen v programme imeet vid:
fp=fopen(name,mode);
Pervym argumentom funkcii fopen yavlyaetsya imya fajla, kotoroe
zadaetsya v vide simvol'noj sroki "name". Vtoroj argument
mode (rezhim) takzhe yavlyaetsya simvol'noj strokoj, kotoraya uka-
zyvaet, kak etot fajl budet ispol'zovat'sya. Dopustimymi
rezhimami yavlyayutsya: chtenie (r), zapis' (w) i dobavlenie (a),
vozmozhen eshche simvol + sprava (naprimer, r+), kotoryj ozna-
chaet, chto vozmozhno i chtenie, i zapis' v fajl.
Esli vy otkroete fajl, kotoryj eshche ne sushchestvuet, dlya
zapisi ili dobavleniya, to takoj fajl budet sozdan (esli eto
vozmozhno). Otkrytie sushchestvuyushchego fajla na zapis' privodit
k otbrasyvaniyu ego starogo soderzhimogo. Popytka chteniya nesu-
shchestvuyushchego fajla yavlyaetsya oshchibkoj. Oshibki mogut byt' obus-
lovleny i drugimi prichinami (naprimer, popytka chteniya iz
fajla, ne imeya na to razresheniya). Pri nalichii kakoj-libo
oshibki funkciya vozvrashchaet nulevoe znachenie ukazatelya NULL
(kotoroe dlya udobstva takzhe opredelyaetsya v fajle stdio.h).
Drugoj neobhodimoj veshch'yu yavlyaetsya sposob chteniya ili
zapisi, esli fajl uzhe otkryt. Zdes' imeetsya neskol'ko voz-
mozhnostej, iz kotoryh getc i putc yavlyayutsya prostejshimi.
Funkciya getc schityvaet iz fajla sleduyushchij simvol; ej neobho-
dim ukazatel' fajla, chtoby znat', iz kakogo fajla chitat'.
Obrashchenie: c=getc(fp)
pomeshchaet v c sleduyushchij simvol iz fajla, ukazannogo posredst-
vom fp, i EOF, esli dostignut konec fajla.
Funkciya putc: putc(c,fp)
pomeshchaet simvol c v fajl fp i vozvrashchaet c. Podobno funkciyam
getchar i putchar, getc i putc mogut byt' makrosami, a ne
funkciyami.
Pri zapuske programmy avtomaticheski otkryvayutsya tri
fajla, kotorye snabzheny opredelennymi ukazatelyami fajlov.
|timi fajlami yavlyayutsya standartnyj vvod, standartnyj vyvod i
standartnyj vyvod oshibok; sootvetstvuyushchie ukazateli fajlov
nazyvayutsya stdin, stdout i stderr. Obychno vse eti ukazateli
svyazany s terminalom, no stdin i stdout mogut byt' perenap-
ravleny na fajly ili v mezhprocessnyj kanal.
Funkcii getchar i putchar mogut byt' opredeleny v ter-
minah getc, putc, stdin i stdout sleduyushchim obrazom:
#define getchar() getc(stdin)
#define putchar(c) putc(c, stdout)
-60-
Pri rabote s fajlami dlya formatnogo vvoda i vyvoda mozhno
ispol'zovat' funkcii fscanf i fprintf. Oni identichny funk-
ciyam scanf i printf, za isklyucheniem togo, chto pervym argu-
mentom yavlyaetsya ukazatel' fajla, opredelyayushchij tot fajl,
kotoryj budet chitat'sya ili kuda budet vestis' zapis'; uprav-
lyayushchaya stroka budet vtorym argumentom.
Ukazateli fajlov stdin i stdout zaranee opredeleny v
biblioteke vvoda-vyvoda kak standartnyj vvod i standartnyj
vyvod; oni mogut byt' ispol'zovany v lyubom meste, gde mozhno
ispol'zovat' ob容kt tipa FILE *. Oni, odnako, yavlyayutsya kons-
tantami, a ne peremennymi, tak chto ih nel'zya izmenyat'.
Funkciya fclose yavlyaetsya obratnoj po otnosheniyu k fopen;
ona razryvaet svyaz' mezhdu ukazatelem fajla i vneshnim imenem,
ustanovlennuyu funkciej fopen, i vysvobozhdaet ukazatel' fajla
dlya drugogo fajla. V operacionnoj sisteme imeyutsya ograniche-
niya na chislo odnovremenno otkrytyh fajlov, kotorymi mozhet
rasporyazhat'sya programma. Funkciya fclose zakryvaet fajl, a
takzhe vyzyvaet vydachu informacii iz bufera, v kotorom putc
sobiraet vyvod (pri normal'nom zavershenii programmy funkciya
fclose vyzyvaetsya avtomaticheski dlya kazhdogo otkrytogo
fajla).
13.7. Obrabotka oshibok - stderr i exit
Pri pechati diagnosticheskih soobshchenij zhelatel'no, chtoby
oni postupali na terminal, dazhe esli standartnyj vyvod pos-
tupaet v nekotoryj fajl ili v mezhprocessnyj kanal.
CHtoby luchshe obrabatyvat' takuyu situaciyu, k programme
tochno takim zhe obrazom, kak stdin i stdout, avtomaticheski
prisoedinyaetsya vtoroj vyhodnoj fajl, nazyvaemyj stderr. Esli
eto voobshche vozmozhno, vyvod, zapisannyj v fajle stderr, poyav-
lyaetsya na terminale pol'zovatelya, dazhe esli standartnyj
vyvod napravlyaetsya v drugoe mesto (na samom dele imeetsya
vozmozhnost' napravit' takie soobshcheniya v fajl, no etogo ne
proishodit pri prostom perenapravlenii standartnogo vyvoda).
Programma mozhet takzhe ispol'zovat' funkciyu exit iz
standartnoj biblioteki, obrashchenie k kotoroj vyzyvaet zaver-
shenie vypolneniya programmy. Argument funkcii exit dostupen
programme, vyzvavshej programmu pol'zovatelya v kachestve pod-
zadachi, tak chto ona mozhet proverit' uspeshnoe ili neudachnoe
zavershenie dannoj programmy. Po soglasheniyu, velichina 0 v
kachestve vozvrashchaemogo znacheniya svidetel'stvuet o tom, chto
vse v poryadke, a razlichnye nenulevye znacheniya yavlyayutsya priz-
nakami nenormal'nyh situacij.
Funkciya exit vyzyvaet funkciyu fclose dlya kazhdogo otkry-
togo vyhodnogo fajla, s tem chtoby vyvesti vsyu pomeshchennuyu v
bufery vyhodnuyu informaciyu, a zatem vyzyvaet funkciyu _exit.
Funkciya _exit privodit k nemedlennomu zaversheniyu bez ochistki
-61-
kakih-libo buferov; konechno, pri zhelanii k etoj funkcii
mozhno obratit'sya neposredstvenno.
Standartnaya biblioteka soderzhit funkciyu fgets. V
rezul'tate obrashcheniya
fgets(line, maxline, fp)
sleduyushchaya stroka vvoda (vklyuchaya simvol novoj stroki) schity-
vaetsya iz fajla fp v simvol'nyj massiv line; samoe bol'shee
maxline-1 simvol budet prochitan. Rezul'tiruyushchaya stroka
zakanchivaetsya simvolom \0. Obychno funkciya fgets vozvrashchaet
line; v konce fajla ona vozvrashchaet NULL.
Prednaznachennaya dlya vyvoda funkciya fputs zapisyvaet
stroku (kotoraya ne obyazana soderzhat' simvol novoj stroki) v
fajl:
fputs(line, fp)
Funkcii gets i puts yavlyayutsya uproshchennymi variantami
fgets i fputs, kotorye rabotayut s fajlami standartnogo
vvoda i vyvoda i ne proveryayut dlinu stroki; gets ne zapisy-
vaet simvol novoj stroki v pamyat', a puts dopisyvaet etot
simvol v fajl v konce stroki:
gets(line)
puts(line)
Standartnaya biblioteka soderzhit funkciyu, vozvrashchayushchuyu
poslednij schitannyj simvol. V rezul'tate obrashcheniya
ungetc(c,fp)
simvol c vozvrashchaetsya v fajl fp. Pozvolyaetsya vozvrashchat' v
kazhdyj fajl tol'ko odin simvol.
13.10. Raznye standartnye funkcii
Standartnaya biblioteka predostavlyaet mnozhestvo raznoob-
raznyh funkcij, nekotorye iz kotoryh okazyvayutsya osobenno
poleznymi.
13.10.1. Upravlenie pamyat'yu
Funkciya calloc sluzhit dlya zaprosov pamyati. V rezul'-
tate obrashcheniya
-62-
calloc(n, sizeof(object))
vozvrashchaetsya libo ukazatel' prostranstva, dostatochnogo dlya
razmeshcheniya n ob容ktov ukazannogo razmera, libo NULL, esli
zapros ne mozhet byt' udovletvoren. Otvodimaya pamyat' inicia-
liziruetsya nulevymi znacheniyami. Funkciya malloc delaet to zhe
samoe, no pamyat' zadaetsya v bajtah:
malloc(size)
Ukazatel' obladaet nuzhnym dlya rassmatrivaemyh ob容ktov
vyravnivaniem, no emu sleduet pripisyvat' sootvetstvuyushchij
tip, kak v sleduyushchem primere
char *calloc();
int *ip;
ip=(int*) calloc(n,sizeof(int));
Funkciya free(p) osvobozhdaet prostranstvo, na kotoroe
ukazyvaet p, prichem ukazatel' p pervonachal'no dolzhen byt'
poluchen v rezul'tate obrashcheniya k calloc. Zdes' net nikakih
ogranichenij na poryadok osvobozhdeniya prostranstva, no osvo-
bozhdenie chego libo, ne poluchennogo s pomoshch'yu calloc ili mal-
loc, privodit k tyazhelym oshibkam.
13.10.2. Standartnye funkcii yazyka Si
V standartnuyu biblioteku funkcij na yazyke Si vhodit,
pomimo opisannyh, mnozhestvo samyh raznyh funkcij. Podrobnoe
opisanie ih privedeno v rukovodstve programmistu po OS
DEMOS, chast' 4 (bibliotechnye funkcii), i v operativnoj doku-
mentacii (man(3)). Nizhe v skobkah privedeny nazvaniya razde-
lov operativnoj dokumentacii, v kotoryh imeyutsya sootvetstvu-
yushchie opisaniya:
- operacii so strokami (string);
- preobrazovanie dannyh bez sscanf i sprintf" (atoi,
itoa, atof, ftoa);
- matematicheskie funkcii (sin, exp, ...);
- proverka i preobrazovanie simvolov (ctype);
- i mnogoe drugoe.
* 14. VZAIMODEJSTVIE S OPERACIONNOJ SISTEMOJ
-63-
14.1. Podgotovka programm na Si v OS DEMOS
V operacionnoj sisteme DEMOS programmy mogut sostoyat'
iz odnogo ili neskol'kih modulej, napisannyh na yazykah Si,
Fortran-77, Assembler. Dlya translyacii i sborki programm na
yazyke Si sluzhit komanda cc. V prostejshem sluchae translyaciya
osushchestvlyaetsya po komande:
cc fajl1.c fajl2.c ...
gde fajl1.c, fajl2.c, ... - imena fajlov, soderzhashchih prog-
rammy na yazyke Si (imena takih fajlov dolzhny okanchivat'sya na
suffiks .c). Komanda osushchestvlyaet translyaciyu perechislennyh
programm i ih ob容dinenie redaktorom svyazej. Esli translya-
ciya proshla bez oshibok, sozdaetsya ispolnyaemyj fajl a.out,
kotoryj mozhno zapustit' na schet, vvedya komandu:
a.out
(to est' nabrav prosto imya etogo fajla). Translyaciyu chasto
provodyat v dva etapa: snachala transliruyut otdel'nye prog-
rammy, poluchaya ob容ktnye moduli, a zatem ob容dinyayut ih
vmeste (v predydushchem primere eto bylo sdelano avtomaticheski
komandoj cc). Razdel'naya translyaciya vyglyadit primerno tak:
cc fajl1.c fajl2.c ...
cc fajlN.c fajlN1.c ...
cc fajl1.o fajl2.o ... fajlN.o ...
V bolee slozhnom sluchae programma mozhet sostoyat' iz modulej
na raznyh yazykah, rezul'tat translyacii mozhet byt' zapisan v
fajl, otlichnyj ot a.out, mozhno ottranslirovat' programmu dlya
otladki s pomoshch'yu otladchika cdeb, i t.p. Podrobnoe opisanie
vyzova kompilyatora imeetsya v rukovodstve programmista
(cc(1), ld(1)). V obshchem sluchae programmy na Si zapuskayutsya
interpretatorami shell ili cshell komandoj:
imya_fajla argumenty naznachenie_vvoda_vyvoda
gde lyubaya chast', krome imeni fajla, mozhet otsutstvovat'.
Lyubaya programma na Si v OS DEMOS dolzhna soderzhat'
golovnuyu funkciyu s imenem main. Rabota programmy nachinaetsya
s etoj funkcii, prichem informaciya o argumentah komandy pere-
daetsya cherez ee formal'nye parametry.
14.2. Dostup k argumentam komandy
Operacionnaya sistema DEMOS pozvolyaet peredavat' argu-
menty komandy nachinayushchej vypolnyat'sya programme. Kogda funk-
ciya main vyzyvaetsya sistemoj, ona vyzyvaetsya s dvumya argu-
mentami. Pervyj argument (tipa int, uslovno nazyvaemyj argc)
ukazyvaet chislo argumentov v komandnoj stroke, s kotorymi
-64-
proishodit obrashchenie k programme; vtoroj argument (argv)
yavlyaetsya ukazatelem na massiv simvol'nyh strok, soderzhashchih
eti argumenty, po odnomu v stroke.
Samuyu prostuyu illyustraciyu etoj vozmozhnosti i neobhodi-
myh pri etom opisanij daet programma echo, kotoraya prosto
pechataet v odnu stroku argumenty komandnoj stroki, razdelyaya
ih probelami. , Esli dana komanda
echo hello, world
to v rezul'tate poluchim:
hello, world
Po soglasheniyu argv[0] yavlyaetsya imenem, po kotoromu
vyzyvaetsya programma, tak chto argc po men'shej mere raven 1.
V privedennom vyshe primere argc raven 3, a argv[0], argv[1]
i argv[2] ravny sootvetstvenno echo, hello, i world. Pervym
fakticheskim agumentom yavlyaetsya argv[1], a poslednim -
argv[argc-1]. Esli argc raven 1, to za imenem programmy ne
sleduet nikakoj komandnoj stroki argumentov. Vse eto poka-
zano v echo:
main(argc, argv)
int argc;
char *argv[];
{
int i;
for (i = 1; i < argc; i++)
printf("%s%c", argv[i],
(i<argc-1) ? ' ' : '\n');
}
Poskol'ku argv yavlyaetsya ukazatelem na massiv ukazatelej, to
sushchestvuet neskol'ko sposobov napisaniya etoj programmy,
ispol'zuyushchih rabotu s ukazatelem, a ne s indeksaciej mas-
siva. Sleduyushchij primer demonstriruet drugoj variant:
main(argc, argv)
int argc;
char **argv;
{
while (--argc > 0)
printf("%s%c",*++argv,
(argc > 1) ? ' ' : '\n');
}
Krome stroki argumentov, programma poluchaet ot sistemy
nabor peremennyh, opisyvayushchih sredu, v kotoroj ona vypolnya-
etsya. Kazhdaya peremennaya sostoit iz imeni i znacheniya
-65-
(tekstovoj stroki). Naprimer, peremennaya TERM peredaet tip
terminala, s kotorogo programma zapushchena. Dlya zaprosa znache-
niya peremennoj po imeni ispol'zuetsya funkciya getenv:
char *getenv();
par = getenv("imya_peremennoj")
Funkciya vozvrashchaet ukazatel' na stroku - znachenie peremen-
noj, libo NULL, esli imya ne najdeno v opisanii sredy.
* 15. INTERFEJS SISTEMY DEMOS
Vse bez isklyucheniya vozmozhnosti operacionnoj sistemy
DEMOS dostupny iz programm na yazyke Si. Material etoj glavy
otnositsya k interfejsu mezhdu Si-programmami i operacionnoj
sistemoj DEMOS. Material delitsya na sleduyushchie chasti:
vvod/vyvod, sistema fajlov, processy, signaly. Predpolaga-
etsya znanie osnovnyh koncepcij OS DEMOS, a takzhe ponyatij
"fajl", "process", "signal". Podrobnoe opisanie sistemnyh
vyzovov i sootvetstvuyushchih im funkcij iz standartnoj biblio-
teke imeetsya v rukovodstve programmista po OS DEMOS i v ope-
rativnoj dokumentacii (chasti 2 i 3). Naprimer, esli v opi-
sanii govoritsya o funkcii popen(3), to podrobnoe opisanie
sleduet iskat' v rukovodstve programmista, chast' 4, ili v
operativnoj dokumentacii, chast' 3; spravku o funkcii mozhno
poluchit' na terminal, nabrav man 3 popen.
V opisanii biblioteki vvoda/vyvoda byl opisan univer-
sal'nyj interfejs, kotoryj odinakov dlya vsego mnogoobraziya
operacionnyh sistem. Na kazhdoj konkretnoj operacionnoj sis-
teme funkcii standartnoj biblioteki dolzhny byt' napisany v
terminah vvoda-vyvoda, dostupnyh na dannoj mashine. V sleduyu-
shchih razdelah opisan nabor funkcij vvoda/vyvoda nizhnego
urovnya, podderzhivaemyh yadrom operacionnoj sistemy DEMOS.
15.1.1. Deskriptory fajlov
V operacionnoj sisteme DEMOS ves' vvod i vyvod osu-
shchestvlyaetsya posredstvom chteniya fajlov ili ih zapisi, potomu
chto vse periferijnye ustrojstva, vklyuchaya terminal pol'zova-
telya, yavlyayutsya fajlami opredelennoj fajlovoj sistemy. |to
oznachaet, chto odin odnorodnyj interfejs upravlyaet vsemi svya-
zyami mezhdu programmoj i periferijnymi ustrojstvami.
V naibolee obshchem sluchae pered chteniem iz fajla ili
zapis'yu v fajl neobhodimo soobshchit' sisteme o namerenii sde-
lat' eto; etot process nazyvaetsya "otkrytiem" fajla. Sistema
vyyasnyaet, imeet li programma pravo postupat' takim obrazom
(sushchestvuet li etot fajl? imeetsya li razreshenie na obrashche-
nie k nemu?), i esli vse v poryadke, vozvrashchaet v programmu
nebol'shoe polozhitel'noe celoe chislo, nazyvaemoe deskriptorom
-66-
fajla. Vsyakij raz, kogda etot fajl ispol'zuetsya dlya vvoda
ili vyvoda, dlya identifikacii fajla upotreblyaetsya deskriptor
fajla, a ne ego imya (zdes' sushchestvuet primernaya analogiya s
ispol'zovaniem read (5,...) i write (6,...) v Fortrane). Vsya
informaciya ob otkrytom fajle soderzhitsya v sisteme; programma
pol'zovatelya obrashchaetsya k fajlu tol'ko cherez deskriptor
fajla.
Dlya udobstva vypolneniya obychnyh operacij vvoda i vyvoda
s pomoshch'yu terminala pol'zovatelya sushchestvuyut special'nye sog-
lasheniya. Kogda interpretator komand (shell) progonyaet prog-
rammu, on otkryvaet tri fajla, nazyvaemye standartnym vvo-
dom, standartnym vyvodom i standartnym vyvodom oshibok, koto-
rye imeyut sootvetstvenno chisla 0, 1 i 2 v kachestve deskrip-
torov etih fajlov. V normal'nom sostoyanii vse oni svyazany s
terminalom, tak chto esli programma chitaet s deskriptorom
fajla 0 i pishet s deskriptorami fajlov 1 i 2, to ona mozhet
osushchestvlyat' vvod i vyvod s pomoshch'yu terminala, ne zabotyas'
ob otkrytii sootvetstvuyushchih fajlov.
Pol'zovatel' programmy mozhet perenapravlyat' vvod i
vyvod na fajly, ispol'zuya v interpretatore komand simvoly <
i >:
prog < infile > outfile
V etom sluchae interpretator komand izmenit opredelenie
deskriptorov fajlov 0 i 1 s terminala na ukazannye fajly.
Obychno deskriptor fajla 2 ostaetsya svyazannym s terminalom,
tak chto soobshcheniya ob oshibkah mogut postupat' tuda. Podobnye
zamechaniya spravedlivy i togda, kogda vvod i vyvod svyazan s
mezhprocessnym kanalom. Sleduet otmetit', chto v etom sluchae
svyaz' programmy s fajlami izmenyaetsya interpretatorom shell
(ili cshell), a ne programmoj. Sama programma, poka ona
ispol'zuet fajl 0 dlya vvoda i fajly 1 i 2 dlya vyvoda, ne
znaet ni otkuda prihodit ee vvod, ni kuda postupaet ee
vydacha.
15.1.2. Nizkourovnevyj vvod/vyvod.
Samyj nizkij uroven' vvoda/vyvoda v sisteme DEMOS ne
predusmatrivaet ni kakoj-libo buferizacii, ni kakogo-libo
drugogo servisa; on po sushchestvu yavlyaetsya neposredstvennym
obrashcheniem k operacionnoj sisteme. Ves' vvod i vyvod osu-
shchestvlyaetsya dvumya funkciyami: read i write. Pervym argumen-
tom obeih funkcij yavlyaetsya deskriptor fajla. Vtorym argumen-
tom yavlyaetsya bufer v vashej programme, otkuda ili kuda dolzhny
postupat' dannye. Tretij argument - eto chislo podlezhashchih
peresylke bajtov. Obrashcheniya k etim funkciyam imeyut vid:
n_read=read(fd,buf,n);
n_written=write(fd,buf,n);
-67-
Pri kazhdom obrashchenii vozvrashchaetsya schetchik bajtov, ukazyvayu-
shchij fakticheskoe chislo peredannyh bajtov. Pri chtenii vozvra-
shchennoe chislo bajtov mozhet okazat'sya men'she, chem zaproshennoe
chislo. Vozvrashchennoe nulevoe chislo bajtov oznachaet konec
fajla, a "-1" ukazyvaet na nalichie kakoj-libo oshibki. Pri
zapisi vozvrashchennoe znachenie ravno chislu fakticheski zapisan-
nyh bajtov; nesovpadenie etogo chisla s chislom bajtov, koto-
roe predpolagalos' zapisat', obychno svidetel'stvuet ob
oshibke.
Kolichestvo bajtov, podlezhashchih chteniyu ili zapisi, mozhet
byt' sovershenno proizvol'nym. Dvumya samymi rasprostranennymi
velichinami yavlyayutsya "1", chto oznachaet peredachu odnogo sim-
vola za obrashchenie (t.e. bez ispol'zovaniya bufera), i "512",
chto sootvetstvuet fizicheskomu razmeru bloka na mnogih peri-
ferijnyh ustrojstvah. |tot poslednij razmer budet naibolee
effektivnym, no dazhe vvod ili vyvod po odnomu simvolu za
obrashchenie ne budet slishkom dorogim.
Primer. Kopirovanie vvoda na vyvod. V sisteme DEMOS
eta programma budet kopirovat' chto ugodno kuda ugodno,
potomu chto vvod i vyvod mogut byt' perenapravleny na lyuboj
fajl ili ustrojstvo.
#define BUFSIZE 512
main() /*copy input to output*/
{
char buf[BUFSIZE];
int n;
while((n=read(0,buf,BUFSIZE))>0)
write(1,buf,n);
}
Esli razmer fajla ne budet kraten BUFSIZE, to pri ocherednom
obrashchenii k read budet vozvrashcheno men'shee chislo bajtov,
kotorye zatem zapisyvayutsya s pomoshch'yu write; pri sleduyushchem
posle etogo obrashchenii k read budet vozvrashchen nul'.
15.1.3. Otkrytie, sozdanie, zakrytie i udalenie
Vo vseh sluchayah, esli tol'ko ne ispol'zuyutsya opredelen-
nye po umolchaniyu standartnye fajly vvoda, vyvoda i oshibok,
vy dolzhny yavno otkryvat' fajly, chtoby zatem chitat' iz nih
ili pisat' v nih. Dlya etoj celi sushchestvuyut dve funkcii: open
i creat.
Funkciya open ves'ma shodna s funkciej fopen, rassmot-
rennoj vyshe, za isklyucheniem togo, chto vmesto vozvrashcheniya
ukazatelya fajla ona vozvrashchaet deskriptor fajla, kotoryj
yavlyaetsya prosto celym tipa int.
int fd;
fd=open(name,rwmode);
-68-
Kak i v sluchae fopen, argument name yavlyaetsya simvol'noj
strokoj, sootvetstvuyushchej vneshnemu imeni fajla. Odnako argu-
ment, opredelyayushchij rezhim dostupa, otlichen: rwmode ravno: 0 -
dlya chteniya, 1 - dlya zapisi, 2 - dlya chteniya i zapisi. Esli
proishodit kakaya-to oshibka, funkciya open vozvrashchaet "-1"; v
protivnom sluchae ona vozvrashchaet neotricatel'nyj deskriptor
fajla.
Popytka otkryt' fajl, kotoryj ne sushchestvuet, yavlyaetsya
oshibkoj. Funkciya creat predostavlyaet vozmozhnost' sozdaniya
novyh fajlov ili perezapisi staryh. V rezul'tate obrashcheniya:
fd=creat(name,pmode);
vozvrashchaet deskriptor fajla, esli okazalos' vozmozhnym soz-
dat' fajl s imenem name, i "-1" v protivnom sluchae. Sozda-
nie fajla, kotoryj uzhe sushchestvuet, ne yavlyaetsya oshibkoj:
creat usechet ego do nulevoj dliny.
Esli fajl ranee ne sushchestvoval, to creat sozdaet ego s
opredelennym rezhimom zashchity, specificiruemym argumentom
pmode. V sisteme fajlov OS DEMOS s fajlom svyazyvayutsya devyat'
bitov zashchity informacii, kotorye upravlyayut razresheniem na
chtenie, zapis' i vypolnenie dlya vladel'ca fajla, dlya gruppy
vladel'cev i dlya vseh ostal'nyh pol'zovatelej. Takim obra-
zom, trehznachnoe vos'merichnoe chislo naibolee udobno dlya
zapisi rezhima zashchity. Naprimer, chislo 0755 svidetel'stvuet o
razreshenii na chtenie, zapis' i vypolnenie dlya vladel'ca i o
razreshenii na chtenie i vypolnenie dlya gruppy i vseh ostal'-
nyh.
Sushchestvuet ogranichenie (obychno 15 - 25) na kolichestvo
fajlov, kotorye programma mozhet imet' otkrytymi odnovre-
menno. V sootvetstvii s etim lyubaya programma, sobirayushchayasya
rabotat' so mnogimi fajlami, dolzhna byt' podgotovlena k pov-
tornomu ispol'zovaniyu deskriptorov fajlov. Procedura close
preryvaet svyaz' mezhdu deskriptorom fajla i otkrytym fajlom i
osvobozhdaet deskriptor fajla dlya ispol'zovaniya s drugim faj-
lom. Zavershenie vypolneniya programmy cherez exit ili v
rezul'tate vozvrata iz golovnoj funkcii privodit k zakrytiyu
vseh otkrytyh fajlov.
Funkciya udaleniya unlink(filename) udalyaet iz sistemy
fajl s imenem filename (Tochnee, udalyaet imya filename, fajl
udalyaetsya, esli na nego ne ostaetsya ssylok pod drugimi ime-
nam).
15.1.4. Proizvol'nyj dostup - lseek
Obychno pri rabote s fajlami vvod i vyvod osushchestvlyaetsya
posledovatel'no: pri kazhdom obrashchenii k funkciyam read i
write chtenie ili zapis' nachinayutsya s pozicii, neposredst-
venno sleduyushchej za predydushchej obrabotannoj. No pri
-69-
neobhodimosti fajl mozhet chitat'sya ili zapisyvat'sya v lyubom
proizvol'nom poryadke. Obrashchenie k sisteme s pomoshch'yu funkcii
lseek pozvolyaet peredvigat'sya po fajlu, ne proizvodya fakti-
cheskogo chteniya ili zapisi. V rezul'tate obrashcheniya
lseek(fd,offset,origin);
tekushchaya poziciya v fajle s deskriptorom fd peredvigaetsya na
poziciyu offset (smeshchenie), kotoraya otschityvaetsya ot mesta,
ukazyvaemogo argumentom origin (nachalo otscheta). Posleduyushchee
chtenie ili zapis' budut teper' nachinat'sya s etoj pozicii.
Argument offset imeet tip long; fd i origin imeyut tip int.
Argument origin mozhet prinimat' znacheniya 0, 1 ili 2, ukazy-
vaya na to, chto velichina offset dolzhna otschityvat'sya soot-
vetstvenno ot nachala fajla, ot tekushchej pozicii ili ot konca
fajla. Naprimer, chtoby dopolnit' fajl, sleduet pered zapis'yu
najti ego konec:
lseek(fd,0l,2);
chtoby vernut'sya k nachalu, mozhno napisat':
lseek(fd,0l,0);
Obratite vnimanie na argument 0l; ego mozhno bylo by zapisat'
i v vide (long) 0.
Funkciya lseek pozvolyaet obrashchat'sya s fajlami primerno
tak zhe, kak s bol'shimi massivami, tol'ko cenoj bolee medlen-
nogo dostupa.
Primer. Funkciya, schityvayushchaya lyuboe kolichestvo bajtov, nachi-
naya s proizvol'nogo mesta v fajle.
/*chitat' n bajtov s pozicii pos v buf */
get(fd,pos,buf,n)
int fd, n;
long pos;
char *buf;
{
lseek(fd,pos,0); /*get to pos */
return(read(fd,buf,n));
}
15.2. Upravlenie processami
V operacionnoj sisteme DEMOS chasto trebuetsya vyzvat' iz
programmy i vypolnit' v vide otdel'nogo processa druguyu
programmu. Sleduyushchij razdel opisyvaet prostejshij sposob
sdelat' eto, a dalee budut rassmotreny bazovye sredstva
upravleniya processami, imeyushchiesya v OS DEMOS.
-70-
Prostejshij sposob vyzvat' druguyu programmu - ispol'zo-
vat' standartnuyu funkciyu system:
system("komandnaya stroka")
Funkciya imeet odin parametr - stroku, kotoruyu ona analizi-
ruet i vypolnyaet tochno tak zhe, kak vypolnyayutsya komandy, vvo-
dimye interpretatorom shell s terminala. Funkciya vypolnyaet
komandu i vozvrashchaet celoe chislo - kod otveta vypolnennoj
komandy (0, esli vse konchilos' normal'no). V komandnoj
stroke vosprinimayutsya lyubye simvoly upravleniya
vvodom/vyvodom >, <, i t.p.
Sleduet uchest', chto, esli v programme vyvod buferizu-
etsya, to pered vyzovom funkcii system neobhodimo vytolknut'
bufera, naprimer vyzvav funkciyu fflush.
15.2.2. Vyzov programmy na nizkom urovne - execl
Vyzov programmy v OS DEMOS osushchestvlyaetsya s pomoshch'yu
neskol'kih elementarnyh funkcij, odna iz kotoryh - funkciya
execl - osushchestvlyaet vyzov novoj programmy vmesto uzhe vypol-
nyayushchejsya, bez vozvrata v vyzyvayushchuyu programmu. Obrashchenie v
nej imeet vid:
execl(komanda,arg0,arg1,...,argN,NULL);
gde "komanda" - stroka simvolov, tochno imenuyushchaya fajl vyzy-
vaemoj komandy. Naprimer, dlya vyzova komandy pr neobhodimo
ukazat' imya /bin/pr. Ostal'nye argumenty takzhe predstavlyayut
soboj stroki simvolov i prosto peredayutsya komande v kachestve
argumentov, pri etom arg0 obychno predstavlyaet soboj prosto
sokrashchennoe imya komandy, a ostal'nye argumenty - parametry
dannoj komandy.
Vyzov execl v sluchae normal'nogo zapuska novoj prog-
rammy zamenyaet eyu tekushchuyu programmu, upravlenie iz funkcii
execl vozvrashchaetsya tol'ko v sluchae oshibki (naprimer, ne naj-
dena komanda s ukazannym imenem). V biblioteke imeetsya
celyj nabor funkcij, osushchestvlyayushchih to zhe samoe i otlichayu-
shchihsya tol'ko predstavleniem parametrov (execl(2), execv(2),
execvp(2), ...) i tem, chto nekotorye funkcii osushchestvlyayut
poisk komandy v standartnom nabore spravochnikov.
15.2.3. Porozhdenie novogo processa - fork
Dlya togo, chtoby zapustit' parallel'no novuyu programmu,
neobhodimo prezhde vsego umet' zapuskat' parallel'nyj pro-
cess. Dlya etogo v OS DEMOS sluzhit funkciya "fork" (razvet-
vit'sya):
-71-
proc_id = fork()
Programma razdelyaetsya na dve identichnye kopii, kotorye pro-
dolzhayut vypolnyat'sya kak dva nezavisimyh processa. Odna iz
programm - process "syn" - poluchaet ot funkcii fork kod
otveta 0, drugaya - "roditel'" - poluchaet nomer, pod kotorym
zapushchen process "syn". V prostejshem sluchae dlya zapuska
parallel'noj programmy vyzov fork kombiniruetsya s execl sle-
duyushchim obrazom:
if( fork() == 0)
{ /* |to process - syn */
... nastrojka fajlov ...
execl(... );
/*Syuda my popadaem pri oshibke v execl */
perror("Ne mogu zapustit' process");
exit(1);
}
... prodolzhenie osnovnoj programmy ...
Zdes' programma posle vyzova fork analiziruet, v kakom pro-
cesse ("roditel'" ili "syn") ona vypolnyaetsya i, v zavisi-
mosti ot etogo, vedet sebya po raznomu. Esli osnovnaya prog-
ramma dolzhna zhdat' okonchaniya "syna", to ona dolzhna vyzvat'
funkciyu wait:
int status;
...
if( fork() == 0)
{ ... execl(...); exit(1);
}
wait(&status));
Funkciya wait vozvrashchaet identifikator processa - "syna", i
zasylaet v peremennuyu status kod zaversheniya etogo processa.
Kod zaversheniya sostoit iz dvuh chastej - mladshie 8 bitov for-
miruyutsya sistemoj i oboznachayut prichinu okonchaniya processa; v
sluchae normal'nogo okonchaniya po funkcii exit" oni soderzhat
0. Starshie 8 bitov v sluchae, esli programma okonchilas' v
rezul'tate vyzova exit, berutsya iz argumenta vyzova funkcii
exit; obychno peredaetsya 0 pri normal'nom zavershenii i chislo,
otlichnoe ot nulya, v sluchae kakih libo oshibok.
Ni fork, ni execl ne zatragivayut otkrytyh fajlov, posle
fork ranee otkrytye fajly nachinayut ispol'zovat'sya oboimi
processami sovmestno, to est' ispol'zuyutsya odni i te zhe uka-
zateli pozicii chteniya/zapisi. Esli novomu processu trebu-
etsya peredat' kakie to otkrytye fajly, ili izmenit' fajly
standartnogo vvoda/vyvoda, nastrojka programmy na eti fajly
delaetsya posle vyzova fork v processe-syne do vyzova execl.
Sleduet zametit', chto pri buferizovannom vvode/vyvode neob-
hodimo sbrosit' bufera pered vyzovom fork(), inache vyvod
nakoplennoj informacii mozhet proizojti dvazhdy - i v
-72-
"roditel'skom", i v novom processe.
15.2.4. Kanal mezhprocessnoj svyazi
Mezhprocessnyj kanal - eto osobyj fajl, ustroennyj takim
obrazom, chto odin process neogranichenno zapisyvaet v nego
informaciyu, a drugoj chitaet, prichem sistema obespechivaet
buferizaciyu dannyh i sinhronizaciyu processov. Mezhprocess-
nye kanaly mogut sozdavat'sya interpretatorom komand shell
ili cshell, naprimer:
ls | pr
Sushchestvuyut bibliotechnye funkcii popen i pclose, pozvolyayushchie
zapustit' parallel'nyj process, kotoryj budet chitat' infor-
maciyu, zapisyvaemuyu v ukazannyj fajl dannym processom, ili,
naprotiv, budet postavlyat' porodivshemu ego processu dannye
dlya chteniya (sm. popen(3)). |ti funkcii ispol'zuyut bazovye
vozmozhnosti postroeniya kanalov, kotorye podderzhivayutsya ope-
racionnoj sistemoj.
Dlya sozdaniya kanala mezhprocessnoj svyazi sluzhit funkciya
pipe:
int fd[2];
...
stat = pipe(fd);
if(stat == -1) /* Byla oshibka */...
Zdes' fd - massiv, v kotoryj zasylaetsya dva deskriptora faj-
lov - fd[1] dlya zapisi v kanal, fd[0] dlya chteniya iz kanala.
|ti deskriptory mogut ispol'zovat'sya naravne s deskriptorami
obychnyh fajlov.
Sinhronizaciya obmenov postroena takim obrazom, chto,
esli process chitaet pustoj kanal, on budet zhdat' poyavleniya
dannyh; esli v kanale ostalos' mnogo neschitannoj informacii,
zapisyvayushchij process budet zhdat' osvobozhdeniya mesta v
kanale. Nakonec, esli u kanala storona dlya zapisi zakryta,
pri chtenii budet poluchen kod otveta "0" - konec fajla.
Kak pravilo, programma sozdaet kanal po zaprosu pipe,
posle chego razdelyaetsya na dve kopii s pomoshch'yu funkcii fork.
Zatem v odnom iz poluchivshihsya processov zakryvaetsya storona
kanala dlya chteniya, v drugom - zakryvaetsya deskriptor zapisi
v kanal. Teper' posle vyzova execl nachinaetsya obmen infor-
maciej po mezhprocessnomu kanalu mezhdu parallel'no vypolnyayu-
shchimisya programmami.
V sluchae, esli obmen dolzhen proishodit' cherez standart-
nyj vvod ili vyvod, ispol'zuetsya funkciya dup dlya svyazyvaniya
deskriptorov fajlov. Naprimer, sleduyushchij fragment programmy
sluzhit dlya zapuska programmy pr tak, chtoby dannye na
-73-
standartnyj vvod programmy pr postupali iz standartnogo
vyvoda osnovnoj programmy:
int fd[2];
#define R 0
#define W 1
pipe(fd);
if(fork() == 0)
{ close(fd[W]); close(0); dup(fd[R]);
close(fd[R]);
execl("/bin/pr","pr",NULL);
exit(1); /* Esli oshibka v execl */
}
close(fd[R]); close(1); dup(fd[W]);
close(fd[W]);
.... schet, pri zapisi proveryaem, ne bylo
.... li oshibki zapisi.
close(1);
V etom primere polnost'yu opushchena obrabotka vozmozhnyh oshibok.
Dlya svyazyvaniya deskriptorov standartnogo vvoda ili vyvoda s
kanalom mezhprocessnoj svyazi zdes' ispol'zovana funkciya
dup(fd)", kotoraya vozvrashchaet duplikat deskriptora fd, prichem
ispol'zuetsya naimen'shij svobodnyj deskriptor fajla. Sledo-
vatel'no, posle zakrytiya fajla s deskriptorom 0 blizhajshee
obrashchenie k funkcii dup svyazhet deskriptor 0 s zadannym v
argumente dup deskriptorom. Posle vyzova dup nenuzhnyj
bol'she deskriptor fd[0] ili fd[1] zakryvayut.
15.3. Signaly i preryvaniya
Normal'nyj hod vypolneniya programmy v OS DEMOS mozhet
preryvat'sya "signalami". Signaly mogut poyavlyat'sya kak v
rezul'tate dejstviya vneshnih prichin (naprimer, v rezul'tate
nazhatiya na terminale klavishi, interpretiruemoj sistemoj kak
"preryvanie" - interupt), tak i v rezul'tate oshibok prog-
rammy.
Funkciya, izmenyayushchaya prinyatye po umolchaniyu dejstviya po
signalu, nazyvaetsya signal i imeet dva argumenta. Pervyj
specificiruet signal, a vtoroj predstavlyaet soboj libo
ssylku na funkciyu, libo special'noe vyrazhenie, oznachayushchee
trebovanie "ignorirovat'" signal libo "standartnaya reakciya
na signal". Uslovnye oboznacheniya zapisany v fajle vstavok
signal.h:
#include <signal.h>
signal (SIGNAL,REAKCIYA)
SIGNAL - eto odin iz standartnyh kodov signalov, naprimer
SIGINT, SIGKILL, ... (podrobnee sm. signal(2)). REAKCIYA -
eto libo ssylka na funkciyu, kotoraya budet vyzvana pri polu-
chenii signala, libo odin iz identifikatorov:
-74-
SIG_IGN - ignorirovat',
SIG_DFL - po umolchaniyu.
Vo vseh sluchayah funkciya signal vozvrashchaet staroe znachenie
opisatelya REAKCIYA. Sushchestvuyut nekotorye tonkosti, kotorye
illyustriruyutsya sleduyushchim fragmentom programmy:
#include <signal.h>
main()
{
int onintr(); /* Opisanie obyazatel'no */
if(signal(SIGINT,SIG_IGN) != SIG_IGN)
{ signal(SIGINT, onintr); }
...
exit(0);
}
onintr()
{ unlink(tempfile);
exit(1);
}
Proverka (if(signal...) svyazana s tem, chto signal SIGINT
posylaetsya na vse processy, nachatye s dannogo terminala.
Esli programma vypolnyaetsya v fonovom rezhime, interpretator
shell pri zapuske programmy ustanavlivaet v nej ignorirova-
nie signala SIGINT, dlya togo, chtoby s terminala preryvalis'
tol'ko interaktivnye processy. Pereklyuchenie obrabotki sig-
nala SIGINT na funkciyu onintr bez proverki perecherknulo by
vse dejstviya shell po zashchite fonovyh processov.
Eshche odna osobennost' svyazana s vozvratom iz programmy
obrabotki signala. Esli preryvanie proizoshlo vo vremya vypol-
neniya programmy, vozvrat iz funkcii obrabotki preryvaniya
privedet k normal'nomu prodolzheniyu ee vypolneniya. Esli,
odnako, preryvanie prishlo vo vremya operacii chteniya s termi-
nala, operaciya chteniya budet prervana, i proizojdet vozvrat
iz funkcii chteniya read s nulevym schetchikom bajtov. Kak pra-
vilo, funkciya obrabotki preryvanij dolzhna v takih sluchayah
ustanavlivat' kakoj libo flag, a programma chteniya, poluchiv
nulevoj schetchik bajtov posle operacii read, mozhet proverit'
etot flag i ustanovit', chto zhe proizoshlo - dostignut konec
fajla ili bylo preryvanie.
Esli programma obladaet sredstvami reakcii na preryva-
niya i, v to zhe vremya, vyzyvaet drugie programmy, zhelatel'no
upravlyat' reakciej na preryvanie primerno takim obrazom:
-75-
signal(SIGINT, onintr);
...
if(fork() == 0)
{ signal(SIGINT, SIG_DFL);
execl(...)
...
}
signal(SIGINT, SIG_IGN);
wait(&status);
signal(SIGINT, onintr);
V etom sluchae preryvaniya, posylaemye s terminala vo vremya
vypolneniya zapushchennoj parallel'no programmy, budut preryvat'
tol'ko etu programmu.
* 16. SVODKA SINTAKSICHESKIH PRAVIL
|ta svodka sintaksisa yazyka Si prednaznachena skoree dlya
oblegcheniya ponimaniya i ne yavlyaetsya tochnoj formulirovkoj
yazyka.
Osnovnymi vyrazheniyami yavlyayutsya sleduyushchie:
vyrazhenie:
pervichnoe_vyrazhenie
* vyrazhenie
& vyrazhenie
- vyrazhenie
! vyrazhenie
~ vyrazhenie
++ l_znachenie
-- l_znachenie
l_znachenie ++
l_znachenie --
sizeof vyrazhenie
(imya tipa) vyrazhenie
vyrazhenie binarnaya_operaciya
vyrazhenie
vyrazhenie ? vyrazhenie : vyrazhenie
l_znachenie operaciya_prisvaivaniya
vyrazhenie
vyrazhenie , vyrazhenie
-76-
pervichnoe_vyrazhenie:
identifikator
konstanta
stroka
^ (vyrazhenie)
pervichnoe_vyrazhenie (spisok vyrazhenij)
neob
pervichnoe_vyrazhenie [vyrazhenie]
l_znachenie . Identifikator
pervichnoe vyrazhenie -> identifikator
l_znachenie:
identifikator
pervichnoe_vyrazhenie [vyrazhenie]
l_znachenie . Identifikator
pervichnoe_vyrazhenie -> identifikator
* vyrazhenie
(l_znachenie)
Operacii pervichnyh vyrazhenij
() [] . ->
imeyut samyj vysokij prioritet i gruppiruyutsya sleva napravo.
Unarnye operacii
* & - ! ~ ++ -- sizeof(imya tipa)
imeyut bolee nizkij prioritet, chem operacii pervichnyh vyrazhe-
nij, no bolee vysokij, chem prioritet lyuboj binarnoj opera-
cii. |ti operacii gruppiruyutsya sprava nalevo. Uslovnaya ope-
raciya gruppiruetsya sprava nalevo, vse binarnye operacii
gruppiruyutsya sleva napravo i ih prioritet ubyvaet v sleduyu-
shchem poryadke:
binarnaya operaciya:
* / %
+ -
>> <<
< > <= >=
== !=
&
~
|
&&
||
?:
Vse operacii prisvaivaniya imeyut odinakovyj prioritet i grup-
piruyutsya sprava nalevo:
= += -= *= ?= %= >>= <<= &= ~= |=
Operaciya zapyataya imeet samyj nizkij prioritet i gruppiruetsya
-77-
sleva napravo.
Opisanie:
specifikatory_opisaniya spisok_inicia-
liziruemyh_opisatelej;
neob
Specifikatory_opisaniya:
specifikator_tipa specifikatory_opisaniya
neob
specifikator_klassa_pamyati specifi-
katory_opisaniya
neob
specifikator_klassa_pamyati:
auto
static
extern
register
typedef
specifikator_tipa:
char
short
int
long
unsigned
float
double
specifikator_struktury_ili_ob容dineniya
opredelyayushchee_tip_imya
specifikator_perechisleniya
spisok_inicializiruemyh_opisatelej:
inicializiruemyj_opisatel'
inicializiruemyj_opisatel',spi-
sok_inicializiruemyh_opisatelej
inicializiruemyj_opisatel'
opisatel'_inicializator
neob
opisatel':
identifikator
(opisatel')
* opisatel'
opisatel' ()
-78-
opisatel' [konstantnoe vyrazhenie ]
neob
specifikator_struktury_ili_ob容dineniya:
struct spisok_opisatelej_struktury
struct identifikator {spisok_opi-
sanij_struktury}
struct identifikator
union {spisok_opisanij_struktury}
union identifikator {spisok_opi-
sanij_struktury}
union identifikator
spisok_opisanij_struktury:
opisanie_struktury
opisanie_struktury spisok_opi-
sanij_struktury
opisanie struktury:
specifikator_tipa spisok_opisa-
telej_struktury
spisok_opisatelej_struktury
opisatel'_struktury
opisatel'_struktury,spisok_opisa-
telej_struktury
opisatel'_struktury:
opisatel'
opisatel': konstantnoe vyrazhenie
:konstantnoe_vyrazhenie
inicializator:
= vyrazhenie
= {spisok_inicializatora}
= {spisok_inicializatora}
spisok inicializatora:
vyrazhenie
spisok_inicializatora,spisok_ini-
cializatora
{spisok_inicializatora}
imya_tipa:
specifikator_tipa abstrakt-
nyj_opisatel'
-79-
abstraktnyj_opisatel':
pusto
{abstraktnyj_opisatel'}
* abstraktnyj_opisatel'
abstraktnyj_opisatel' ()
abstraktnyj_opisatel' [konstant-
noe_vyrazhenie]
neob
opredelyayushchee_tip_imya:
identifikator
specifikator_perechisleniya:
enum spisok_perechisleniya
enum identifikator spisok_perechisleniya
enum identifikator
spisok_perechisleniya:
perechislyaemoe
spisok_perechisleniya, perechislyaemoe
perechislyaemoe:
identifikator
identifikator = konstantnoe vyrazhenie
sostavnoj_operator:
{spisok_opisanij spisok_operatorov}
neob neob
spisok_opisanij:
opisanie
opisanie spisok_opisanij
spisok_operatorov:
operator
operator spisok_operatorov
-80-
operator:
sostavnoj operator
vyrazhenie;
if (vyrazhenie) operator
if (vyrazhenie) operator else operator
while (vyrazhenie) operator
do operator while (vyrazhenie);
for(vyrazhenie1;vyrazhenie2;vyrazhenie3)
neob neob neob
operator
switch (vyrazhenie) operator
case konstantnoe_vyrazhenie : operator
default: operator
break;
continue;
return;
return vyrazhenie;
goto identifikator;
identifikator : operator
;
16.4. Vneshnie opredeleniya
programma:
vneshnee_opredelenie
vneshnee_opredelenie programma
vneshnee_opredelenie:
opredelenie_funkcii
opredelenie_dannyh
opredelenie_funkcii:
specifikator_tipa opisatel'_funk-
neob
cii telo_funkcii
opisatel'_funkcii:
opisatel' (spisok_parametrov)
neob
spisok_parametrov:
idetifikator
identifikator , spisok_parametrov
telo_funkcii:
spisok_opisanij_tipa operator_funkcii
operator_funkcii:
{spisok opisanij spisok_operatorov}
neob
-81-
opredelenie dannyh:
extern specifikator_tipa spi-
neob neob
sok inicializiruemyh opisatelej;
neob
static specifikator tipa spisok
neob neob
inicializiruemyh opisatelej;
neob
#define identifikator stroka_leksem
#define identifikator(identifika-
tor,...,identifikator) stroka_leksem
#undef identifikator
#include "imya_fajla"
#include <imya_fajla>
#if konstantnoe_vyrazhenie
#ifdef identifikator
#ifndef identifikator
#else
#endif
#line konstanta "imya_fajla"
neob
* 17. Primery programm na Si
Primer 1: funkcii fgets i fputs (sm. razdel "Standart-
naya biblioteka vvoda/vyvoda. Vvod/vyvod strok").
-82-
#include <stdio.h>
char *fgets(s,n,iop) /*vzyat'<=n simvolov*/
char *s; /* iz iop */
int n;
register FILE *iop;
{
register int c;
register char *cs;
cs = s;
while(--n>0&&(c=getc(iop)) !=EOF)
if ((*cs++ = c)=='\n')
break;
*cs = '\0';
return((c==EOF && cs==s) ? NULL : s);
}
fputs(s,iop) /*pomestit' stroku s v */
register char *s; /* fajl iop */
register FILE *iop;
{
register int c;
while (c = *s++)
putc(c,iop);
}
Primer 2. Programma dlya razdeleniya odnogo bol'shogo fajla na
neskol'ko chastej tak, chtoby kazhdaya chast' nachinalas' so
stroki .sh 1 ...
-83-
#include <stdio.h>
#define NEWH ".sh 1" /*Priznak razdeleniya*/
/* Translyaciya:
cc -o ds ds.c
Zapusk:
ds otkuda kudapref kudasuff
rezul'tat:
ds a pref suff
perepisyvaet fajl a v fajly
pref00.suff, pref01.suff, ...
*/
main (ac,av)
char **av;
{
int nfile=0; /* Poryadkovyj nomer fajla*/
char str[512]; /* Bufer dlya stroki*/
if(ac != 4)
{
fprintf(stderr,
"Nevernoe chislo argumentov0);
exit(1);
}
/* freopen analogichno fopen, no izmenyaet
ukazannyj opisatel' fajla, a ne sozdaet
novyj. Zdes' my pereopredelyaem
stdin */
if(!freopen(av[1],"r",stdin))
{
fprintf(stderr,
"Ne mogu otkryt':%s0,av[1]);
exit(2);
}
/* Pereopredelili fajl stand. vyvoda */
of(av[2],nfile,av[3]);
while( gets(str))
{
/* strncmp(s1,s2,l) sravnivaet dve stroki
i vozvrashchaet 0, esli pervye l simvolov
sovpadayut */
if(strncmp(str,NEWH,strlen(NEWH))== 0)
{
fclose(fp);
nfile++;
/* |to prosto informacionnoe soobshchenie */
fprintf(stderr,
"Nachalo chasti %d0,nfile);
fp = of(av[2],nfile,av[3]);
}
puts(str);
if(ferror(stdout)) {
-84-
fprintf(stderr,
"Osh zapisi v fajl nomer %.2d0,nfile);
exit(4);
}
}
exit (0);
}
/* |ta funkciya sozdaet imya fajla
iz treh chastej i otkryvaet ego
kak standartnyj vyvod */
of(s1,n,s2)
char *s1,*s2;
{
register FILE *f;
char buf[100];
/* sprintf vozvrashchaet svoj pervyj argument */
if(( f = freopen(
sprintf(buf,"%s%02d.%s",s1,n,s2)
,"w",stdout))== NULL)
{
fprintf(stderr,
"Ne mogu otkryt' fajl:%s0,buf);
exit(4);
}
return;
}
-85-
SODERZHANIE
''ANNOTACIYA'' ................... 2
1. VVEDENIE .......................................... 1
2. SINTAKSICHESKAYA NOTACIYA ............................ 3
2.1. Klyuchevye slova .................................. 3
2.2. Konstanty ....................................... 4
2.2.1. Celye konstanty ............................... 4
2.2.2. Dlinnye (long) konstanty ...................... 4
2.2.3. Simvol'nye konstanty .......................... 4
2.2.4. Veshchestvennye konstanty ........................ 5
2.3. Stroki .......................................... 5
2.4. Harakteristiki apparatnyh sredstv ............... 6
3. OB'EKTY YAZYKA SI .................................. 6
3.1. Interpretaciya identifikatorov ................... 6
3.2. Ob容kty i l_znacheniya ............................ 8
3.3. Preobrazovaniya .................................. 8
3.3.1. Simvoly i celye ............................... 8
3.3.2. Tipy float i double ........................... 9
3.3.3. Veshchestvennye i celochislennye velichiny ......... 9
3.3.4. Ukazateli i celye ............................. 9
3.3.5. Celoe bez znaka ............................... 9
3.3.6. Arifmeticheskie preobrazovaniya ................. 10
4. VYRAZHENIYA ......................................... 10
4.1. Pervichnye vyrazheniya ............................. 11
4.2. Unarnye operacii ................................ 13
4.3. Mul'tiplikativnye operacii ...................... 14
4.4. Additivnye operacii ............................. 15
4.5. Operacii sdviga ................................. 16
4.6. Operacii otnosheniya .............................. 16
4.7. Operacii ravenstva .............................. 17
4.8. Pobitovaya operaciya 'i' .......................... 17
4.9. Pobitovaya operaciya isklyuchayushchego 'ili' ........... 17
4.10. Pobitovaya operaciya vklyuchayushchego 'ili' ............ 17
4.11. Logicheskaya operaciya 'i' ......................... 18
4.12. Operaciya logicheskogo 'ili' ...................... 18
4.13. Uslovnaya operaciya ............................... 18
4.14. Operaciya prisvaivaniya ........................... 19
4.15. Prisvaivanie struktury .......................... 20
4.16. Operaciya 'zapyataya' .............................. 20
4.17. Starshinstvo i poryadok vychisleniya. ............... 20
5. OPISANIYA .......................................... 22
5.1. Specifikatory klassa pamyati ..................... 22
5.2. Specifikatory tipa .............................. 23
5.3. Opisateli ....................................... 24
5.4. Smysl opisatelej ................................ 24
-86-
5.5. Opisanie struktur i ob容dinenij ................. 26
5.6. Perechislimyj tip ................................ 29
5.7. Inicializaciya ................................... 30
5.8. Imena tipov ..................................... 32
5.9. Opisatel' typedef ............................... 33
6. OPERATORY ......................................... 34
6.1. Operatornoe vyrazhenie ........................... 34
6.2. Sostavnoj operator (ili blok) ................... 34
6.3. Uslovnye operatory .............................. 35
6.4. Operator while .................................. 35
6.5. Operator do ..................................... 35
6.6. Operator for .................................... 35
6.7. Operator switch ................................. 36
6.8. Operator break .................................. 37
6.9. Operator continue ............................... 37
6.10. Operator vozvrata ............................... 38
6.11. Operator goto ................................... 38
6.12. Pomechennyj operator ............................. 38
6.13. Pustoj operator ................................. 38
7. VNESHNIE OPREDELENIYA ............................... 39
7.1. Vneshnee opredelenie funkcii ..................... 39
7.2. Vneshnie opredeleniya dannyh ...................... 40
8. OBLASTX DEJSTVIYA IDENTIFIKATOROV .................. 40
8.1. Leksicheskaya oblast' dejstviya .................... 41
8.2. Oblast' dejstviya vneshnih identifikatorov ........ 42
8.3. Neyavnye opisaniya ................................ 42
9. PREPROCESSOR YAZYKA 'SI' ........................... 43
9.1. Zamena leksem ................................... 43
9.2. Vklyuchenie fajlov ................................ 44
9.3. Uslovnaya kompilyaciya ............................. 45
9.4. Komanda #line ................................... 45
10. DOPOLNITELXNAYA INFORMACIYA O TIPAH ................. 46
10.1. Struktury i ob容dineniya ......................... 46
10.2. Funkcii ......................................... 47
10.3. Massivy, ukazateli i indeksaciya ................. 47
10.4. YAvnye preobrazovaniya ukazatelej ................. 48
11. KONSTANTNYE VYRAZHENIYA ............................. 49
12. SOOBRAZHENIYA O PERENOSIMOSTI ....................... 49
12.1. Anahronizmy ..................................... 51
13. STANDARTNAYA BIBLIOTEKA VVODA I VYVODA ............. 51
13.1. Obrashchenie k standartnoj biblioteke .............. 52
13.2. Standartnyj vvod i vyvod ........................ 52
13.3. Formatnyj vyvod - funkciya printf ................ 53
13.4. Formatnyj vvod - funkciya scanf .................. 55
13.5. Formatnoe preobrazovanie v pamyati ............... 58
-87-
13.6. Dostup k fajlam ................................. 59
13.7. Obrabotka oshibok - stderr i exit .............. 61
13.8. Vvod i vyvod strok .............................. 62
13.9. Funkciya ungetc .................................. 62
13.10.Raznye standartnye funkcii ...................... 62
13.10.1.Upravlenie pamyat'yu ............................ 62
13.10.2.Standartnye funkcii yazyka Si .................. 63
14. VZAIMODEJSTVIE S OPERACIONNOJ SISTEMOJ ............ 63
14.1. Podgotovka programm na Si v OS DEMOS ............ 64
14.2. Dostup k argumentam komandy ..................... 64
15. INTERFEJS SISTEMY DEMOS ........................... 66
15.1. Vvod/vyvod ...................................... 66
15.1.1. Deskriptory fajlov ............................ 66
15.1.2. Nizkourovnevyj vvod/vyvod. .................... 67
15.1.3. Otkrytie, sozdanie, zakrytie i udalenie ....... 68
15.1.4. Proizvol'nyj dostup - lseek ................... 69
15.2. Upravlenie processami ........................... 70
15.2.1. Funkciya system ................................ 71
15.2.2. Vyzov programmy na nizkom urovne - execl ...... 71
15.2.3. Porozhdenie novogo processa - fork ............. 71
15.2.4. Kanal mezhprocessnoj svyazi ..................... 73
15.3. Signaly i preryvaniya ............................ 74
16. Svodka sintaksicheskih pravil ...................... 76
16.1. Vyrazheniya ....................................... 76
16.2. Opisaniya ........................................ 78
16.3. Operatory ....................................... 80
16.4. Vneshnie opredeleniya ............................. 81
16.5. Preprocessor .................................... 82
17. Primery programm na Si ............................ 82
-88-
Last-modified: Mon, 29 Jun 1998 14:37:17 GMT