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; } 6.8. Operator break 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. 6.9. Operator continue 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.). 6.10. Operator vozvrata 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). 6.11. Operator goto Upravlenie mozhno peredavat' bezuslovno s pomoshch'yu opera- tora goto identifikator1 Identifikator dolzhen byt' metkoj (p. 0.12), lokalizovannoj v dannoj funkcii. 6.12. Pomechennyj operator Pered lyubym operatorom mozhet stoyat' metka, imeyushchaya vid: identifikator: Metki ispol'zuyutsya tol'ko dlya ukazaniya mesta, kuda pereda- etsya upravlenie operatorom goto. Oblast'yu dejstviya metki yavlyaetsya dannaya funkciya, za isklyucheniem teh podblokov, v kotoryh tot zhe identifikator opisan snova. 6.13. Pustoj operator Pustoj operator imeet formu: ; Pustoj operator okazyvaetsya poleznym, tak kak on pozvolyaet postavit' metku pered zakryvayushchej skobkoj } sostavnogo ope- ratora ili ukazat' pustoe telo v operatorah cikla, takih kak while. -38-  * 7. VNESHNIE OPREDELENIYA Si-programma predstavlyaet soboj posledovatel'nost' vneshnih opredelenij. Vneshnee opredelenie opisyvaet identifi- kator kak imeyushchij klass pamyati extern (po umolchaniyu), ili, vozmozhno, static, i specificirovannyj tip. Specifikator tipa takzhe mozhet byt' pustym; v etom sluchae schitaetsya, chto tip yavlyaetsya tipom int. Oblast' dejstviya vneshnih opredelenij rasprostranyaetsya do konca fajla, v kotorom oni privedeny, tochno tak zhe, kak vliyanie opisanij prostiraetsya do konca bloka. Sintaksis vneshnih opredelenij ne otlichaetsya ot sin- taksisa opisanij, za isklyucheniem togo, chto tol'ko na etom urovne mozhno privodit' tekst funkcij. 7.1. Vneshnee opredelenie funkcii Opredelenie funkcii imeet formu opredelenie_funkcii: specifikatory_opisaniya opisa- neob tel'_funkcii telo_funkcii Edinstvennymi specifikatorami klassa pamyati, dopuskaemymi v kachestve specifikatorov-opisaniya, yavlyayutsya extern ili static; o razlichii mezhdu nimi smotri v sleduyushchem razdele. Opisatel' funkcii podoben opisatelyu dlya funkcii, vozvrashchayu- shchej ..., za isklyucheniem togo, chto on perechislyaet formal'nye parametry opredelyaemoj funkcii. opisatel'_funkcii: opisatel' (spisok_parametrov) neob spisok parametrov: identifikator identifikator, spisok_parametrov Telo_funkcii imeet formu telo_funkcii: spisok_opisanij sostavnoj_operator Identifikatory iz spiska parametrov mogut byt' opisany v spiske opisanij. Lyuboj identifikator iz etogo spiska, tip kotorogo ne ukazan, schitaetsya imeyushchim tip int. Edinstvennym dopustimym zdes' specifikatorom klassa pamyati yavlyaetsya register; esli takoj klass pamyati specificirovan, to v nachale vypolneniya funkcii sootvetstvuyushchij fakticheskij para- metr kopiruetsya, esli eto vozmozhno, v registr. Vot prostoj primer polnogo opredeleniya funkcii: -39- int max(a, b, c) int a, b, c; { int m; m = (a>b) ? a:b; return((m>c) ? m:c); } Zdes' int - specifikator-tipa, mah(a,b,c) - opisatel'_funkcii, int a,b,c; - spisok-opisanij formal'nyh parametrov, { ... } - blok, soderzhashchij tekst operatora. V yazyke Si vse fakticheskie parametry tipa float preob- razuyutsya k tipu double, tak chto opisaniya formal'nyh paramet- rov, ob座avlennyh kak float, mogut rabotat' s parametrami tipa double. Analogichno, poskol'ku ssylka na massiv v lyubom kontekste (v chastnosti v fakticheskom parametre) rassmatriva- etsya kak ukazatel' na pervyj element massiva, opisaniya for- mal'nyh parametrov vida massiv ... mogut rabotat' s fakti- cheskimi parametrami tipa ukazatel' na ... I nakonec, pos- kol'ku funkcii ne mogut byt' peredany funkcii, bessmyslenno opisyvat' formal'nyj parametr kak funkciyu (ukazateli na takie ob容kty, konechno, dopuskayutsya). PRIMECHANIE V nekotoryh versiyah yazyka Si, v chastnosti, v versiyah dlya mikroprocessorov, mozhet byt' zapreshchena peredacha struktur i ob容dinenij cherez parametry funkcii. 7.2. Vneshnie opredeleniya dannyh Vneshnee opredelenie dannyh imeet formu: opredelenie_dannyh: opisanie Klassom pamyati takih dannyh mozhet byt' extern (v chastnosti, po umolchaniyu) ili static, no ne auto ili register.  * 8. OBLASTX DEJSTVIYA IDENTIFIKATOROV Vsya Si-programma ne obyazatel'no kompiliruetsya odnovre- menno; ishodnyj tekst programmy mozhet hranit'sya v neskol'kih fajlah i ranee skompilirovannye procedury mogut zagruzhat'sya iz bibliotek. Svyaz' mezhdu funkciyami mozhet osushchestvlyat'sya kak cherez yavnye obrashcheniya, tak i v rezul'tate raboty redaktora svyazej. Poetomu sleduet rassmotret' dva vida oblastej dejstviya: vo pervyh, tu, kotoraya mozhet byt' nazvana leksicheskoj oblast'yu dejstviya identifikatora i kotoraya po sushchestvu yavlyaetsya toj oblast'yu v programme, gde etot identifikator -40- mozhno ispol'zovat', ne vyzyvaya diagnosticheskogo soobshcheniya "neopredelennyj identifikator"; i vo-vtoryh, oblast' dejst- viya, kotoraya svyazana s vneshnimi identifikatorami i kotoraya harakterizuetsya pravilom, chto ssylki na odin i tot zhe vnesh- nij identifikator yavlyayutsya ssylkami na odin i tot zhe ob容kt. 8.1. Leksicheskaya oblast' dejstviya Leksicheskaya oblast' dejstviya identifikatorov, opisannyh vo vneshnih opredeleniyah, prostiraetsya ot opredeleniya do konca ishodnogo fajla, v kotorom on nahoditsya. Leksicheskaya oblast' dejstviya identifikatorov, yavlyayushchihsya formal'nymi parametrami, rasprostranyaetsya na tu funkciyu, k kotoroj oni otnosyatsya. Leksicheskaya oblast' dejstviya identifikatorov, opisannyh v nachale bloka, prostiraetsya do konca etogo bloka. Leksicheskoj oblast'yu dejstviya metok yavlyaetsya ta funkciya, v kotoroj oni nahodyatsya. Poskol'ku vse ssylki na odin i tot zhe vneshnij identifi- kator otnosyatsya k odnomu i tomu zhe ob容ktu, kompilyator pro- veryaet vse opisaniya odnogo i togo zhe vneshnego identifikatora na sovmestimost'; v dejstvitel'nosti ih oblast' dejstviya rasprostranyaetsya na ves' fajl, v kotorom oni nahodyatsya. Vo vseh sluchayah, odnako, esli nekotoryj identifikator yavnym obrazom opisan v nachale bloka, vklyuchaya i blok, kotoryj obrazuet funkciyu, to dejstvie lyubogo opisaniya etogo identi- fikatora vne bloka priostanavlivaetsya do konca etogo bloka. Napomnim takzhe, chto identifikatory, sootvetstvuyushchie obychnym peremennym, s odnoj storony, i identifikatory, soot- vetstvuyushchie chlenam i yarlykam struktur i ob容dinenij, s dru- goj storony, formiruyut dva neperesekayushchihsya klassa, kotorye ne vstupayut v protivorechie. CHleny i yarlyki struktur podchinya- yutsya tem zhe samym pravilam opredeleniya oblastej dejstviya, kak i drugie identifikatory. Imena, specificiruemye s pomoshch'yu typedef, vhodyat v tot zhe klass, chto i obychnye iden- tifikatory. Oni mogut byt' pereopredeleny vo vnutrennih blokah, no vo vnutrennem opisanii tip dolzhen byt' ukazan yavno: typedef float distance; ... { auto int distance; ... Vo vtorom opisanii specifikator tipa int dolzhen prisutstvo- vat', tak kak v protivnom sluchae eto opisanie budet prinyato za opisanie bez opisatelej s tipom distance. -41- 8.2. Oblast' dejstviya vneshnih identifikatorov Esli funkciya ssylaetsya na identifikator, opisannyj kak extern, to gde-to sredi fajlov ili bibliotek, obrazuyushchih polnuyu programmu, dolzhno soderzhat'sya vneshnee opredelenie etogo identifikatora. Vse funkcii dannoj programmy, kotorye ssylayutsya na odin i tot zhe vneshnij identifikator, ssylayutsya na odin i tot zhe ob容kt, tak chto sleduet pozabotit'sya, chtoby specificirovannye v etom opredelenii tip i razmer byli sov- mestimy s tipom i razmerom, ukazyvaemymi v kazhdoj funkcii, kotoraya ssylaetsya na eti dannye. Poyavlenie klyuchevogo slova extern vo vneshnem opredelenii ukazyvaet na to, chto pamyat' dlya opisannyh v nem identifika- torov budet vydelena v drugom fajle. Sledovatel'no, v sosto- yashchej iz mnogih fajlov programme vneshnee opredelenie identi- fikatora, ne soderzhashchee specifikatora extern, dolzhno poyav- lyat'sya tol'ko v odnom iz etih fajlov. Lyubye drugie fajly, kotorye zhelayut dat' vneshnee opredelenie etogo identifika- tora, dolzhny vklyuchat' v eto opredelenie slovo extern. Iden- tifikator mozhet byt' inicializirovan tol'ko v tom opisanii, kotoroe privodit k vydeleniyu pamyati. Iz etogo pravila v OS DEMOS imeetsya isklyuchenie. Vneshnij ob容kt mozhet prisutstvovat' v neskol'kih opisaniyah bez extern. Pri etom dlina ob容kta v raznyh opisaniyah dolzhna sovpadat', a inicializaciya, esli ona est', dolzhna provo- dit'sya rovno v odnom iz opisanij. Pri narushenii etih pravil budet vydana oshibka na etape redaktirovanii svyazej prog- rammy. Identifikatory, vneshnee opredelenie kotoryh nachinaetsya so slova static, nedostupny iz drugih fajlov. Funkcii mogut byt' opisany kak static. 8.3. Neyavnye opisaniya Ne vsegda neobhodimo specificirovat' i klass pamyati i tip identifikatora v opisanii. Vo vneshnih opredeleniyah i opisaniyah formal'nyh parametrov i chlenov struktur klass pamyati opredelyaetsya po kontekstu. Esli v nahodyashchemsya vnutri funkcii opisanii ne ukazan tip, a tol'ko klass pamyati, to predpolagaetsya, chto identifikator imeet tip int; esli ne ukazan klass pamyati, a tol'ko tip, to identifikator predpo- lagaetsya opisannym kak auto. Isklyuchenie iz poslednego pra- vila daetsya dlya funkcij, potomu chto specifikator auto dlya funkcij yavlyaetsya bessmyslennym (yazyk Si ne v sostoyanii kom- pilirovat' programmu v stek); esli identifikator imeet tip funkciya, vozvrashchayushchaya ..., to on predpolagaetsya neyavno opi- sannym kak extern. Vhodyashchij v vyrazhenie i neopisannyj ranee identifikator, za kotorym sleduet skobka (, schitaetsya opisannym po -42- kontekstu kak funkciya, vozvrashchayushchaya int. /* extern */ int tab[100]; static /* int */ t1; /* int */ func(i) /* int i; */ { register /* int */ k; /* auto */ char buf[512]; /* extern int f1(); */ ... f1(a,b) ...  * 9. PREPROCESSOR YAZYKA 'SI' Kompilyator yazyka Si soderzhit preprocessor, kotoryj poz- volyaet osushchestvlyat' makropodstanovki, uslovnuyu kompilyaciyu i vklyuchenie imenovannyh fajlov. Stroki, nachinayushchiesya s #, yavlyayutsya komandami etogo preprocessora. Sintaksis etih strok ne svyazan s ostal'nym yazykom; oni mogut poyavlyat'sya v lyubom meste i ih vliyanie rasprostranyaetsya (nezavisimo ot oblasti dejstviya) do konca ishodnogo programmnogo fajla. Fakticheski preprocessor rasshiryaet vozmozhnosti yazyka Si, realizuya takie funkcii, kotorye v drugih yazykah vhodyat v sostav samogo yazyka (naprimer, parametricheskie konstanty v Fortrane-77). 9.1. Zamena leksem 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. 9.2. Vklyuchenie fajlov Komanda #include "filename" privodit k zamene etoj stroki na vse soderzhimoe fajla s ime- nem filename. Fajl s etim imenem snachala ishchetsya v tekushchem spravochnike, a zatem v drugih "standartnyh" mestah, oprede- lyaemyh pol'zovatelem pri vyzove kompilyatora. V otlichie ot etogo komanda #include <filename> ishchet fajl tol'ko v standartnom spravochnike sistemy. V OS DEMOS fajl ishchetsya v spravochnike /usr/include. Komandy #include mogut byt' vlozhennymi. -44- 9.3. Uslovnaya kompilyaciya Komanda preprocessora #if konstantnoe vyrazhenie proveryaet, otlichno li ot nulya znachenie konstantnogo vyrazhe- niya. Komanda: #ifdef identifikator proveryaet, opredelen li etot identifikator v nastoyashchij moment v preprocessore, t.e. opredelen li etot identifikator s pomoshch'yu komandy #define. Komanda: #ifndef identifikator proveryaet, yavlyaetsya li etot identifikator v dannyj moment ne opredelennym dlya preprocessora. Za kazhdym iz treh perechislennyh vidov strok mozhet sle- dovat' proizvol'noe chislo strok, vozmozhno soderzhashchih komandu preprocessora #else a zatem dolzhna sledovat' komanda: #endif Esli proveryaemoe uslovie istinno, to lyubye stroki mezhdu #else i #endif ignoriruyutsya. Esli proveryaemoe uslovie lozhno, to lyubye stroki mezhdu proveryaemoj strokoj i #else ili, pri otsutstvii #else, #endif ignoriruyutsya. |ti konstrukcii mogut byt' vlozhennymi. Naprimer: #ifdef DEBUG fprintf(stderr,"i=%o j=%d\n",i,j); #endif Peremennaya preprocessora mozhet byt' opredelena ne tol'ko v samoj programme, no i pri vyzove translyatora. 9.4. Komanda #line Dlya drugih preprocessorov, generiruyushchih Si-programmy, polezna sleduyushchaya komanda: #line konstanta "imya_fajla" -45- kotoraya soobshchaet kompilyatoru (dlya diagnosticheskih soobshche- nij), chto sleduyushchaya stroka ishodnogo fajla imeet nomer, zadavaemyj konstantoj, i chto tekushchij vhodnoj fajl imenuetsya imenem_fajla. Esli imya_fajla otsutstvuet, to zapominaemoe imya fajla ne izmenyaetsya. Primer: #line 250 "gram.y"  * 10. DOPOLNITELXNAYA INFORMACIYA O TIPAH V etom razdele obobshchayutsya svedeniya ob operaciyah, koto- rye mozhno primenyat' tol'ko k ob容ktam opredelennyh tipov. 10.1. Struktury i ob容dineniya So strukturami i ob容dineniyami mogut proizvodit'sya sle- duyushchie operacii: ssylka na odin iz chlenov struktury ili ob容dineniya (s pomoshch'yu operacii .), poluchenie adresa (s pomoshch'yu unarnoj operacii &), prisvaivanie struktury struk- ture, peredacha struktury v kachestve formal'nogo parametra, vozvrat struktury funkciej. Vse ostal'nye operacii zapre- shcheny. V realizacii vozvrashcheniya struktur funkciyami na CM-|VM imeetsya kovarnyj defekt: esli vo vremya vozvrata proishodit preryvanie i ta zhe samaya funkciya reenterabel'no vyzyvaetsya vo vremya etogo preryvaniya, to znachenie, vozvrashchaemoe iz per- vogo vyzova, mozhet byt' isporcheno. |ta trudnost' mozhet voz- niknut' tol'ko pri nalichii istinnogo preryvaniya, kak iz ope- racionnoj sistemy, tak i iz programmy pol'zovatelya; preryva- niya, kotoroe dejstvitel'no asinhronno; obychnye rekursivnye vyzovy sovershenno bezopasny. V razdele "Vyrazheniya" govoritsya, chto pri pryamoj ili kosvennoj ssylke na strukturu (s pomoshch'yu . ili ->) imya sprava dolzhno byt' chlenom konstrukcii, nazvannoj ili ukazan- noj vyrazheniem sleva. |to ogranichenie ne navyazyvaetsya strogo kompilyatorom, chtoby dat' vozmozhnost' obojti pravila soot- vetstviya tipov. V dejstvitel'nosti pered . dopuskaetsya lyuboe l_znachenie i zatem predpolagaetsya, chto eto l_znachenie imeet formu struktury, dlya kotoroj stoyashchee sprava imya yavlya- etsya chlenom. Takim zhe obrazom, ot vyrazheniya, stoyashchego pered ->, trebuetsya tol'ko byt' ukazatelem ili celym. V sluchae ukazatelya predpolagaetsya, chto on ukazyvaet na strukturu, dlya kotoroj stoyashchee sprava imya yavlyaetsya chlenom. V sluchae celogo ono rassmatrivaetsya kak absolyutnyj adres sootvetstvuyushchej struktury, zadannyj v edinicah mashinnoj pamyati. Takie struktury ne yavlyayutsya perenosimymi. -46- 10.2. Funkcii Tol'ko dve operacii mozhno primenyat' k funkcii: vyzvat' ee ili izvlech' ee adres. Esli imya funkcii vhodit v vyrazhenie ne v pozicii imeni funkcii, sootvetstvuyushchej obrashcheniyu k nej, to generiruetsya ukazatel' na etu funkciyu. Sledovatel'no, chtoby peredat' odnu funkciyu drugoj, mozhno napisat' int f(); ... g(f); togda opredelenie funkcii g moglo by vyglyadet' tak: g(funcp) int (*funcp)(); { ... (*funcp)(); ... } Obratite vnimanie, chto v vyzyvayushchej procedure funkciya f dolzhna byt' opisana yavno, potomu chto za ee poyavleniem v g(f) ne sleduet skobka "(". 10.3. Massivy, ukazateli i indeksaciya Kazhdyj raz, kogda identifikator, imeyushchij tip massiva, poyavlyaetsya v vyrazhenii, on preobrazuetsya v ukazatel' na per- vyj chlen etogo massiva. Iz-za etogo preobrazovaniya massivy ne yavlyayutsya l_znacheniyami. Po opredeleniyu operaciya indeksacii "[]" interpretiruetsya takim obrazom, chto e1[e2] schitaetsya identichnym vyrazheniyu *((e1)+(e2)). Soglasno pravilam preob- razovanij, primenyaemym pri operacii +, esli e1 - massiv, a e2 - celoe, to e1[e2] ssylaetsya na e2-j chlen massiva e1. Poetomu, nesmotrya na nesimmetrichnyj vid, operaciya indeksacii yavlyaetsya kommutativnoj. V sluchae mnogomernyh massivov primenyaetsya analogichnoe pravilo. Esli e yavlyaetsya n-mernym massivom razmera i*j*...*k, to pri poyavlenii v vyrazhenii e preobrazuetsya v ukazatel' na (n-1)-mernyj massiv razmera j*...*k. Esli ope- raciya * libo yavno, libo neyavno, kak rezul'tat indeksacii, primenyaetsya k etomu ukazatelyu, to rezul'tatom operacii budet ukazannyj (n-1)-mernyj massiv, kotoryj sam nemedlenno preob- razuetsya v ukazatel'. Rassmotrim, naprimer, opisanie: int u[3][5]; Zdes' u - massiv celyh razmera 3*5. Pri poyavlenii v -47- vyrazhenii u preobrazuetsya v ukazatel' na pervyj iz treh mas- sivov iz 5 celyh. V vyrazhenii u[i], kotoroe ekvivalentno *(u+i), snachala u preobrazuetsya v ukazatel' tak, kak opisano vyshe; zatem i preobrazuetsya k tipu u, chto vyzyvaet umnozhenie i na dlinu ob容kta, na kotoryj ukazyvaet ukazatel', a imenno na 5 celyh ob容ktov. Rezul'taty skladyvayutsya, i primenenie kosvennoj adresacii daet massiv (iz 5 celyh), kotoryj v svoyu ochered' preobrazuetsya v ukazatel' na pervoe iz etih celyh. Esli v vyrazhenie vhodit i drugoj indeks, to ta zhe samaya argumentaciya primenyaetsya snova; rezul'tatom na etot raz budet celoe. Iz vsego etogo sleduet, chto massivy v yazyke Si hranyatsya postrochno (poslednij indeks izmenyaetsya bystree vsego) i chto pervyj indeks v opisanii pomogaet opredelit' obshchee koli- chestvo pamyati, trebuemoe dlya hraneniya massiva, no ne igraet nikakoj drugoj roli v vychisleniyah, svyazannyh s indeksaciej. 10.4. YAvnye preobrazovaniya ukazatelej Razreshayutsya opredelennye preobrazovaniya s ispol'zova- niem ukazatelej. Oni imeyut nekotorye zavisyashchie ot konkret- noj realizacii aspekty. Vse eti preobrazovaniya zadayutsya s pomoshch'yu operacii yavnogo preobrazovaniya tipa. Ukazatel' mozhet byt' preobrazovan v lyuboj iz celochis- lennyh tipov, dostatochno bol'shoj dlya ego hraneniya. Trebuetsya li pri etom int ili long, zavisit ot konkretnoj mashiny (v OS DEMOS dlya SM |VM trebuetsya int). Preobrazuyushchaya funkciya takzhe yavlyaetsya mashinno-zavisimoj, no ona budet vpolne estestvennoj dlya teh, kto znaet strukturu adresacii v mashine. Detali dlya nekotoryh konkretnyh mashin privodyatsya nizhe. Ob容kt celochislennogo tipa mozhet byt' yavnym obrazom preobrazovan v ukazatel'. Takoe preobrazovanie vsegda pere- vodit preobrazovannoe iz ukazatelya celoe v tot zhe samyj uka- zatel', no v drugih sluchayah ono budet mashinno-zavisimym. Ukazatel' na odin tip mozhet byt' preobrazovan v ukaza- tel' na drugoj tip. Esli preobrazuemyj ukazatel' ne ukazy- vaet na ob容kty, kotorye podhodyashchim obrazom vyravneny v pamyati, to rezul'tiruyushchij ukazatel' mozhet pri ispol'zovanii vyzyvat' oshibki adresacii. Garantiruetsya, chto ukazatel' na ob容kt zadannogo razmera mozhet byt' preobrazovan v ukazatel' na ob容kt men'shego razmera i snova obratno, ne preterpev pri etom izmeneniya. Naprimer, procedura raspredeleniya pamyati alloc mogla by prinimat' zapros na razmer vydelyaemogo ob容kta v bajtah, a vozvrashchat' ukazatel' na simvoly; eto mozhno bylo by ispol'zo- vat' sleduyushchim obrazom. -48- extern char *alloc(); double *dp; dp=(double*) alloc(sizeof(double)); *dp=22.0/7.0; Funkciya alloc dolzhna obespechivat' (mashinno-zavisimym sposo- bom), chto vozvrashchaemoe eyu znachenie budet podhodyashchim dlya pre- obrazovaniya v ukazatel' na double; v takom sluchae ispol'zo- vanie etoj funkcii budet perenosimym. Predstavlenie ukazatelya na CM-|VM sootvetstvuet 16- bitovomu celomu i izmeryaetsya v bajtah. Ob容kty tipa char ne imeyut nikakih ogranichenij na vyravnivanie; vse ostal'nye ob容kty dolzhny imet' chetnye adresa.  * 11. KONSTANTNYE VYRAZHENIYA V neskol'kih mestah v yazyke Si trebuyutsya vyrazheniya, kotorye posle vychisleniya stanovyatsya konstantami: posle vari- antnogo prefiksa case, v kachestve granic massivov i v inici- alizatorah. V pervyh dvuh sluchayah vyrazhenie mozhet soderzhat' tol'ko celye konstanty, simvol'nye konstanty i vyrazheniya sizeof, vozmozhno svyazannye libo binarnymi operaciyami + - * / . % & | ^ << >> == 1= <> <= >= libo unarnymi operaciyami - ~ libo ternarnoj operaciej ?: Kruglye skobki mogut ispol'zovat'sya dlya gruppirovki, no ne dlya obrashcheniya k funkciyam. V sluchae inicializatorov dopuskaetsya bol'shaya (udarenie na bukvu o) svoboda; krome perechislennyh vyshe konstantnyh vyrazhenij mozhno takzhe primenyat' unarnuyu operaciyu & k vneshnim ili staticheskim ob容ktam i k vneshnim ili staticheskim massi- vam, imeyushchim v kachestve indeksov konstantnoe vyrazhenie. Unarnaya operaciya & mozhet byt' takzhe primenena neyavno, v rezul'tate poyavleniya neindeksirovannyh massivov i funkcij. Osnovnoe pravilo zaklyuchaetsya v tom, chto posle vychisleniya inicializator dolzhen stanovitsya libo konstantoj, libo adre- som ranee opisannogo vneshnego ili staticheskogo ob容kta plyus ili minus konstanta.  * 12. SOOBRAZHENIYA O PERENOSIMOSTI Odnim iz dostoinstv yazyka Si schitaetsya perenosimost' programm na Si, kotoraya svyazana kak s otnositel'noj mashinnoj -49- nezavisimost'yu samogo yazyka, tak i s sovmestimost'yu sredy, obespechivaemoj sovmestimymi s OS UNIX operacionnymi siste- mami. Vmeste s tem, pri napisanii na yazyke Si takih prog- ramm, kotorye ne dolzhny zaviset' ot konkretnoj |VM, neobho- dimo uchityvat' to, chto nekotorye chasti yazyka Si po svoej suti mashinno-zavisimy. Sleduyushchee nizhe perechislenie potenci- al'nyh trudnostej hotya i ne yavlyayutsya vseob容mlyushchimi, no vydelyaet osnovnye iz nih. Voprosy, celikom svyazannye s apparatnym oborudovaniem, takie kak razmer slova, svojstva veshchestvennoj arifmetiki i celogo deleniya, ne predstavlyayut osobennyh zatrudnenij. Dru- gie aspekty apparatnyh sredstv nahodyat svoe otrazhenie v raz- lichnyh realizaciyah. Nekotorye iz nih, v chastnosti, znakovoe rasshirenie (preobrazuyushchee otricatel'nyj simvol v otricatel'- noe celoe) i poryadok, v kotorom pomeshchayutsya bajty v slove, predstavlyayut soboj nepriyatnost', kotoraya dolzhna tshchatel'no otslezhivat'sya. Bol'shinstvo ostal'nyh problem etogo tipa ne vyzyvaet skol'ko_nibud' znachitel'nyh zatrudnenij. CHislo peremennyh tipa register, kotoroe fakticheski mozhet byt' pomeshcheno v registry, menyaetsya ot mashiny k mashine, takzhe kak i nabor dopustimyh dlya nih tipov. Tem ne menee vse kompilyatory na svoih mashinah rabotayut nadlezhashchim obrazom; lishnie ili nedopustimye registrovye opisaniya ignoriruyutsya. Nekotorye trudnosti voznikayut tol'ko pri ispol'zovanii somnitel'noj praktiki programmirovaniya, ili pri ispol'zova- nii osobennostej konkretnoj realizacii. Pisat' programmy, kotorye zavisyat ot takih osobennostej, chrezvychajno nera- zumno. YAzykom ne ukazyvaetsya poryadok vychisleniya argumentov funkcij; oni vychislyayutsya sprava nalevo na CM-|VM i |VM PDP- 11 i VAXR-11 firmy DEC i sleva napravo na bol'shinstve ostal'nyh mashin. Poryadok, v kotorom proishodyat pobochnye effekty, takzhe ne specificiruetsya. Tak kak simvol'nye konstanty v dejstvitel'nosti yavlya- yutsya ob容ktami tipa int, dopuskaetsya ispol'zovanie simvol'- nyh konstant, sostoyashchih iz neskol'kih simvolov. Odnako, pos- kol'ku poryadok, v kotorom simvoly pripisyvayutsya k slovu, menyaetsya ot mashiny k mashine, konkretnaya realizaciya okazyva- etsya ves'ma mashinno_zavisimoj. Poryadok prisvaivaniya polej k slovam i simvolov k celym takzhe zavisit ot |VM. Takie razlichiya nezametny dlya izoliro- vannyh programm, v kotoryh ne razresheno smeshivat' tipy (pre- obrazuya, naprimer, ukazatel' na int v ukazatel' na char i zatem proveryaya ukazyvaemuyu pamyat'), no dolzhny uchityvat'sya pri soglasovanii s nakladyvaemymi izvne shemami pamyati. -50- YAzyk, prinyatyj na razlichnyh kompilyatorah, otlichaetsya tol'ko neznachitel'nymi detalyami. Samoe zametnoe otlichie sos- toit v tom, chto ispol'zuemyj v nastoyashchee vremya kompilyator na CM-|VM ne inicializiruet struktury, kotorye soderzhat polya bitov, ne imeet tipa "unsigned char" i imeet nekotorye ogra- nicheniya na operacii prisvaivaniya v opredelennyh kontekstah, svyazannyh s ispol'zovaniem znacheniya prisvaivaniya struktur. 12.1. Anahronizmy V staryh programmah mozhno vstretit' nekotorye ustarev- shie konstrukcii. Hotya bol'shinstvo versij kompilyatora podder- zhivaet takie anahronizmy, oni v konce koncov ischeznut, osta- viv za soboj tol'ko problemy perenosimosti. V rannih versiyah Si dlya problem prisvaivaniya ispol'zo- valas' forma =op, a ne op=, privodya k dvusmyslennostyam, tipichnym primerom kotoryh yavlyaetsya h =-1 gde h fakticheski umen'shaetsya, poskol'ku operacii = i - pri- mykayut drug k drugu, no chto vpolne moglo rassmatrivat'sya i kak prisvaivanie -1 k h. Sintaksis inicializatorov izmenilsya: ran'she znak ravenstva, s kotorogo nachinaetsya inicializator, otsutstvo- val, tak chto vmesto int h = 1; ispol'zovalos' int h 1; izmenenie bylo vneseno iz_za inicializacii int f (1+2) kotoraya dostatochno sil'no napominaet opredelenie funkcii, chtoby smutit' kompilyatory.  * 13. STANDARTNAYA BIBLIOTEKA VVODA I VYVODA Sredstva vvoda/vyvoda ne yavlyayutsya sostavnoj chast'yu yazyka Si. V etoj glave budet opisana "standartnaya biblio- teka vvoda/vyvoda", to est' nabor funkcij, razrabotannyh dlya obespecheniya standartnoj sistemy vvoda/vyvoda dlya Si- prog- ramm. |ti funkcii otrazhayut tol'ko te operacii, kotorye mogut byt' obespecheny na bol'shinstve sovremennyh operacionnyh sis- tem. Procedury dostatochno effektivny dlya togo, chtoby pol'zo- vateli redko chuvstvovali neobhodimost' obojti ih "radi -51- effektivnosti", kak by ni byla vazhna konkretnaya zadacha. I nakonec, eti procedury byli zadumany avtorami yazyka "pereno- simymi" v tom smysle, chto oni dolzhny sushchestvovat' v sovmes- timom vide na lyuboj sisteme, gde imeetsya yazyk Si, i chto programmy, kotorye ogranichivayut svoi vzaimodejstviya s sis- temnymi vozmozhnostyami, predostavlyaemymi standartnoj biblio- tekoj, mozhno budet perenosit' s odnoj sistemy na druguyu po sushchestvu bez izmenenij. Dalee opisyvayutsya osnovnye principy organizacii vvoda/vyvoda v programmah na yazyke Si, ispol'zuyushchih biblio- teku vvoda/vyvoda. Polnoe opisanie etoj biblioteki imeetsya v rukovodstve programmista (chast' 4) ili v operativnoj doku- mentacii ("man(3)"). Programmy, rabotayushchie v OS DEMOS, mogut takzhe obrashchat'sya k funkciyam vvoda/vyvoda nizkogo urovnya, kotorye realizovany neposredstvenno v yadre OS DEMOS, no takaya neobhodimost' voznikaet dostatochno redko. 13.1. Obrashchenie k standartnoj biblioteke Kazhdyj ishodnyj fajl, kotoryj obrashchaetsya k funkcii iz standartnoj biblioteki, dolzhen gde to v nachale soderzhat' stroku #include <stdio.h> V fajle stdio.h opredelyayutsya nekotorye makrosy i peremennye, ispol'zuemye bibliotekoj vvoda/vyvoda. 13.2. Standartnyj vvod i vyvod Samyj prostoj mehanizm vvoda zaklyuchaetsya v chtenii po odnomu simvolu za raz iz "standartnogo vvoda" (obychno s ter- minala pol'zovatelya) s pomoshch'yu funkcii getchar. Funkciya getchar() celogo tipa pri kazhdom k nej obrashchenii vozvrashchaet sleduyushchij vvodimyj simvol. V bol'shinstve sistem, kotorye podderzhivayut yazyk Si, terminal mozhet byt' zamenen nekotorym fajlom s pomoshch'yu oboznacheniya "<". Esli nekotoraya programma prog ispol'zuet funkciyu getchar, to komandnaya stroka prog <infile privedet k tomu, chto prog budet chitat' iz fajla infile, a ne s terminala. Pereklyuchenie vvoda delaetsya takim obrazom, chto sama programma prog ne zamechaet izmeneniya; v chastnosti stroka "<infile" ne vklyuchaetsya v komandnuyu stroku argumentov (sm. sleduyushchuyu glavu). Pereklyuchenie vvoda okazyvaetsya neza- metnym i v tom sluchae, kogda vyvod postupaet iz drugoj prog- rammy cherez mezhprocessnyj kanal. Naprimer, komandnaya stroka otherprog | prog progonyaet dve programmy, otherprog i prog, tak, chto -52- standartnym vvodom dlya prog sluzhit standartnyj vyvod other- prog. Funkciya getchar vozvrashchaet znachenie EOF, kogda dostiga- etsya konec fajla, kakoj by vvod ona pri etom ne schityvala. Standartnaya biblioteka polagaet simvolicheskuyu konstantu EOF ravnoj -1 (posredstvom #define v fajle stdio.h), no proverki sleduet pisat' v terminah EOF, a ne -1, chtoby izbezhat' zavi- simosti ot konkretnogo znacheniya. Vyvod mozhno osushchestvlyat' s pomoshch'yu funkcii putchar(c), pomeshchayushchej simvol 'c' v "standartnyj vyvod", kotoryj po umolchaniyu yavlyaetsya terminalom. Vyvod mozhno pri vyzove prog- rammy napravit' v nekotoryj fajl s pomoshch'yu oboznacheniya ">". Esli prog ispol'zuet putchar, to komandnaya stroka prog > outfile privedet k zapisi standartnogo vyvoda v fajl outfile, a ne na terminal. V sisteme DEMOS mozhno takzhe ispol'zovat' mezhp- rocessnyj kanal. V standartnoj biblioteke vvoda/vyvoda "funkcii" getchar i putchar na samom dele mogut byt' makrosami. |to pozvolyaet izbezhat' nakladnyh rashodov na obrashchenie k funkcii dlya obra- botki kazhdogo simvola. 13.3. Formatnyj vyvod - funkciya printf Dve funkcii: printf dlya vyvoda i scanf dlya vvoda (sle- duyushchij razdel) pozvolyayut preobrazovyvat' chislennye velichiny v simvol'noe predstavlenie i obratno. Oni takzhe pozvolyayut generirovat' i interpretirovat' formatnye stroki. Funkciya printf(control, arg1, arg2, ...) preobrazuet argumenty v tekstovuyu formu v sootvetstvii s formatami, zadannymi v upravlyayushchej stroke control, i vydaet rezul'tat v standartnyj vyvod. Upravlyayushchaya stroka soderzhit dva tipa ob容ktov: obychnye simvoly, kotorye prosto kopiru- yutsya v vyhodnoj potok, i specifikacii preobrazovanij, kazhdaya iz kotoryh vyzyvaet preobrazovanie i pechat' ocherednogo argu- menta printf. Kazhdaya specifikaciya preobrazovaniya nachinaetsya s simvola "%" i zakanchivaetsya simvolom preobrazovaniya (bukvoj, oprede- lyayushchej tip preobrazovaniya). Mezhdu "%" i simvolom preobrazo- vaniya mogut nahodit'sya: - Znak minus, kotoryj vyzyvaet vyravnivanie preobrazo- vannogo argumenta po levomu krayu polya. -53- - Stroka cifr, zadayushchaya minimal'nuyu shirinu polya. Preob- razovannoe chislo budet napechatano v pole po krajnej mere etoj shiriny, a esli neobhodimo, to i v bolee shirokom. Esli preobrazovannyj argument imeet men'she simvolov, chem ukazannaya shirina polya, to on budet dopolnen sleva (ili sprava, esli bylo ukazano vyrav- nivanie po levomu krayu) zapolnyayushchimi simvolami do etoj shiriny. Zapolnyayushchim simvolom obychno yavlyaetsya probel, a esli shirina polya ukazyvaetsya s lidiruyushchim nulem, to etim simvolom budet nul' (lidiruyushchij nul' v dannom sluchae ne oznachaet vos'merichnoj shiriny polya). - Tochka, kotoraya otdelyaet shirinu polya ot sleduyushchej stroki cifr. - Stroka cifr (tochnost'); ukazyvaet maksimal'noe chislo simvolov stroki, kotorye dolzhny byt' napechatany, ili chislo pechataemyh sprava ot desyatichnoj tochki cifr dlya peremennyh tipa float ili double. - Modifikator dliny l, kotoryj ukazyvaet, chto soot- vetstvuyushchij element dannyh imeet tip long, a ne int. Nizhe privodyatsya simvoly preobrazovaniya i ih smysl: d - argument preobrazuetsya k desyatichnomu vidu; o - argument preobrazuetsya v bezznakovuyu vos'merichnuyu formu (bez lidiruyushchego nulya); x - argument preobrazuetsya v bezznakovuyu shestnadcaterich- nuyu formu (bez lidiruyushchih 0h); u - argument preobrazuetsya v bezznakovuyu desyatichnuyu formu; c - argument rassmatrivaetsya kak otdel'nyj simvol; s - argument yavlyaetsya strokoj: simvoly stroki pechatayutsya do teh por, poka ne budet dostignut nulevoj simvol ili ne budet napechatano kolichestvo simvolov, ukazan- noe v specifikacii tochnosti; e - argument, rassmatrivaemyj kak peremennaya tipa float ili double, preobrazuetsya v desyatichnuyu formu v vide [-]m.nnnnnne[+-]hh, gde dlina stroki iz n opredelya- etsya ukazannoj tochnost'yu. Tochnost' po umolchaniyu ravna 6; f - argument, rassmatrivaemyj kak peremennaya tipa float ili double, preobrazuetsya v desyatichnuyu formu v vide [-]mmm.nnnnn, gde dlina stroki iz n opredelyaetsya uka- zannoj tochnost'yu. Tochnost' po umolchaniyu ravna 6. -54- Otmetim, chto eta tochnost' ne opredelyaet kolichestvo pechataemyh v formate f znachashchih cifr; g - ispol'zuetsya ili format %e ili %f, kakoj koroche; nez- nachashchie nuli ne pechatayutsya. Vmesto "ld"mozhno ispol'zovat' "D", vmesto "lo" - "O", vmesto "lx" - "X". Esli idushchij za % simvol ne yavlyaetsya simvolom preobrazo- vaniya, to pechataetsya sam etot simvol; sledovatel'no,simvol % mozhno napechatat', ukazav %%. Bol'shinstvo iz formatnyh preobrazovanij ochevidno. Edinstvennym isklyucheniem yavlyaetsya to, kak tochnost' vzaimo- dejstvuet so strokami. Sleduyushchaya tablica demonstriruet vliya- nie razlichnyh specifikacij na pechat' "hello, world" (12 sim- volov). Vokrug kazhdogo polya pomeshcheny dvoetochiya dlya togo, chtoby mozhno bylo opredelit' ego protyazhennost'. :%10s: :hello, world: :%10-s: :hello, world: :%20s: : hello,