Ocenite etot tekst:



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



     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.



     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.



     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.



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



     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 |
          |_______________________________________|





     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.



     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.



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



     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.



     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-




     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.



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



     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.



         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.



         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.



         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.



         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.



             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.



       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-




     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-




     Struktury mogut byt' prisvoeny, a takzhe peredany  funk-
ciyam  v  kachestve  argumentov  i  vozvrashcheny funkciyami. Tipy
uchastvuyushchih operandov dolzhny sovpadat'.



         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.



     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.



     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.



     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.



     bol'shinstvo operatorov yavlyayutsya operatornymi  vyrazheni-
yami, kotorye imeyut formu

                vyrazhenie;

Obychno operatornye  vyrazheniya  yavlyayutsya  prisvaivaniyami  ili
obrashcheniyami k funkciyam.



     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.



     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-




     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.



     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.



     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.



     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.



     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-




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




     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-




     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"




     V etom razdele obobshchayutsya svedeniya ob operaciyah,  koto-
rye mozhno primenyat' tol'ko k ob容ktam opredelennyh tipov.



     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 "(".



     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.



     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.



     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.



     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.



     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.



     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.



     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.



     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.



     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);



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



     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.



     Standartnaya biblioteka predostavlyaet mnozhestvo raznoob-
raznyh  funkcij,  nekotorye  iz kotoryh okazyvayutsya osobenno
poleznymi.



     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.



     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.



                            -63-




     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.



     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.



     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.



     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.



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



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



     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));
        }




     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.



     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.



     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.



     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.



     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.



     |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
        ;



    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




     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
Ocenite etot tekst: