sya odni i te zhe uka- zateli pozicii chteniya/zapisi. Esli novomu processu trebu- etsya peredat' kakie to otkrytye fajly, ili izmenit' fajly standartnogo vvoda/vyvoda, nastrojka programmy na eti fajly delaetsya posle vyzova fork v processe-syne do vyzova execl. Sleduet zametit', chto pri buferizovannom vvode/vyvode neob- hodimo sbrosit' bufera pered vyzovom fork(), inache vyvod nakoplennoj informacii mozhet proizojti dvazhdy - i v -72- "roditel'skom", i v novom processe. 15.2.4. Kanal mezhprocessnoj svyazi Mezhprocessnyj kanal - eto osobyj fajl, ustroennyj takim obrazom, chto odin process neogranichenno zapisyvaet v nego informaciyu, a drugoj chitaet, prichem sistema obespechivaet buferizaciyu dannyh i sinhronizaciyu processov. Mezhprocess- nye kanaly mogut sozdavat'sya interpretatorom komand shell ili cshell, naprimer: ls | pr Sushchestvuyut bibliotechnye funkcii popen i pclose, pozvolyayushchie zapustit' parallel'nyj process, kotoryj budet chitat' infor- maciyu, zapisyvaemuyu v ukazannyj fajl dannym processom, ili, naprotiv, budet postavlyat' porodivshemu ego processu dannye dlya chteniya (sm. popen(3)). |ti funkcii ispol'zuyut bazovye vozmozhnosti postroeniya kanalov, kotorye podderzhivayutsya ope- racionnoj sistemoj. Dlya sozdaniya kanala mezhprocessnoj svyazi sluzhit funkciya pipe: int fd[2]; ... stat = pipe(fd); if(stat == -1) /* Byla oshibka */... Zdes' fd - massiv, v kotoryj zasylaetsya dva deskriptora faj- lov - fd[1] dlya zapisi v kanal, fd[0] dlya chteniya iz kanala. |ti deskriptory mogut ispol'zovat'sya naravne s deskriptorami obychnyh fajlov. Sinhronizaciya obmenov postroena takim obrazom, chto, esli process chitaet pustoj kanal, on budet zhdat' poyavleniya dannyh; esli v kanale ostalos' mnogo neschitannoj informacii, zapisyvayushchij process budet zhdat' osvobozhdeniya mesta v kanale. Nakonec, esli u kanala storona dlya zapisi zakryta, pri chtenii budet poluchen kod otveta "0" - konec fajla. Kak pravilo, programma sozdaet kanal po zaprosu pipe, posle chego razdelyaetsya na dve kopii s pomoshch'yu funkcii fork. Zatem v odnom iz poluchivshihsya processov zakryvaetsya storona kanala dlya chteniya, v drugom - zakryvaetsya deskriptor zapisi v kanal. Teper' posle vyzova execl nachinaetsya obmen infor- maciej po mezhprocessnomu kanalu mezhdu parallel'no vypolnyayu- shchimisya programmami. V sluchae, esli obmen dolzhen proishodit' cherez standart- nyj vvod ili vyvod, ispol'zuetsya funkciya dup dlya svyazyvaniya deskriptorov fajlov. Naprimer, sleduyushchij fragment programmy sluzhit dlya zapuska programmy pr tak, chtoby dannye na -73- standartnyj vvod programmy pr postupali iz standartnogo vyvoda osnovnoj programmy: int fd[2]; #define R 0 #define W 1 pipe(fd); if(fork() == 0) { close(fd[W]); close(0); dup(fd[R]); close(fd[R]); execl("/bin/pr","pr",NULL); exit(1); /* Esli oshibka v execl */ } close(fd[R]); close(1); dup(fd[W]); close(fd[W]); .... schet, pri zapisi proveryaem, ne bylo .... li oshibki zapisi. close(1); V etom primere polnost'yu opushchena obrabotka vozmozhnyh oshibok. Dlya svyazyvaniya deskriptorov standartnogo vvoda ili vyvoda s kanalom mezhprocessnoj svyazi zdes' ispol'zovana funkciya dup(fd)", kotoraya vozvrashchaet duplikat deskriptora fd, prichem ispol'zuetsya naimen'shij svobodnyj deskriptor fajla. Sledo- vatel'no, posle zakrytiya fajla s deskriptorom 0 blizhajshee obrashchenie k funkcii dup svyazhet deskriptor 0 s zadannym v argumente dup deskriptorom. Posle vyzova dup nenuzhnyj bol'she deskriptor fd[0] ili fd[1] zakryvayut. 15.3. Signaly i preryvaniya Normal'nyj hod vypolneniya programmy v OS DEMOS mozhet preryvat'sya "signalami". Signaly mogut poyavlyat'sya kak v rezul'tate dejstviya vneshnih prichin (naprimer, v rezul'tate nazhatiya na terminale klavishi, interpretiruemoj sistemoj kak "preryvanie" - interupt), tak i v rezul'tate oshibok prog- rammy. Funkciya, izmenyayushchaya prinyatye po umolchaniyu dejstviya po signalu, nazyvaetsya signal i imeet dva argumenta. Pervyj specificiruet signal, a vtoroj predstavlyaet soboj libo ssylku na funkciyu, libo special'noe vyrazhenie, oznachayushchee trebovanie "ignorirovat'" signal libo "standartnaya reakciya na signal". Uslovnye oboznacheniya zapisany v fajle vstavok signal.h: #include <signal.h> signal (SIGNAL,REAKCIYA) SIGNAL - eto odin iz standartnyh kodov signalov, naprimer SIGINT, SIGKILL, ... (podrobnee sm. signal(2)). REAKCIYA - eto libo ssylka na funkciyu, kotoraya budet vyzvana pri polu- chenii signala, libo odin iz identifikatorov: -74- SIG_IGN - ignorirovat', SIG_DFL - po umolchaniyu. Vo vseh sluchayah funkciya signal vozvrashchaet staroe znachenie opisatelya REAKCIYA. Sushchestvuyut nekotorye tonkosti, kotorye illyustriruyutsya sleduyushchim fragmentom programmy: #include <signal.h> main() { int onintr(); /* Opisanie obyazatel'no */ if(signal(SIGINT,SIG_IGN) != SIG_IGN) { signal(SIGINT, onintr); } ... exit(0); } onintr() { unlink(tempfile); exit(1); } Proverka (if(signal...) svyazana s tem, chto signal SIGINT posylaetsya na vse processy, nachatye s dannogo terminala. Esli programma vypolnyaetsya v fonovom rezhime, interpretator shell pri zapuske programmy ustanavlivaet v nej ignorirova- nie signala SIGINT, dlya togo, chtoby s terminala preryvalis' tol'ko interaktivnye processy. Pereklyuchenie obrabotki sig- nala SIGINT na funkciyu onintr bez proverki perecherknulo by vse dejstviya shell po zashchite fonovyh processov. Eshche odna osobennost' svyazana s vozvratom iz programmy obrabotki signala. Esli preryvanie proizoshlo vo vremya vypol- neniya programmy, vozvrat iz funkcii obrabotki preryvaniya privedet k normal'nomu prodolzheniyu ee vypolneniya. Esli, odnako, preryvanie prishlo vo vremya operacii chteniya s termi- nala, operaciya chteniya budet prervana, i proizojdet vozvrat iz funkcii chteniya read s nulevym schetchikom bajtov. Kak pra- vilo, funkciya obrabotki preryvanij dolzhna v takih sluchayah ustanavlivat' kakoj libo flag, a programma chteniya, poluchiv nulevoj schetchik bajtov posle operacii read, mozhet proverit' etot flag i ustanovit', chto zhe proizoshlo - dostignut konec fajla ili bylo preryvanie. Esli programma obladaet sredstvami reakcii na preryva- niya i, v to zhe vremya, vyzyvaet drugie programmy, zhelatel'no upravlyat' reakciej na preryvanie primerno takim obrazom: -75- signal(SIGINT, onintr); ... if(fork() == 0) { signal(SIGINT, SIG_DFL); execl(...) ... } signal(SIGINT, SIG_IGN); wait(&status); signal(SIGINT, onintr); V etom sluchae preryvaniya, posylaemye s terminala vo vremya vypolneniya zapushchennoj parallel'no programmy, budut preryvat' tol'ko etu programmu.  * 16. SVODKA SINTAKSICHESKIH PRAVIL |ta svodka sintaksisa yazyka Si prednaznachena skoree dlya oblegcheniya ponimaniya i ne yavlyaetsya tochnoj formulirovkoj yazyka. 16.1. Vyrazheniya 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. 16.2. Opisaniya 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 16.3. Operatory sostavnoj_operator: {spisok_opisanij spisok_operatorov} neob neob spisok_opisanij: opisanie opisanie spisok_opisanij spisok_operatorov: operator operator spisok_operatorov -80- operator: sostavnoj operator vyrazhenie; if (vyrazhenie) operator if (vyrazhenie) operator else operator while (vyrazhenie) operator do operator while (vyrazhenie); for(vyrazhenie1;vyrazhenie2;vyrazhenie3) neob neob neob operator switch (vyrazhenie) operator case konstantnoe_vyrazhenie : operator default: operator break; continue; return; return vyrazhenie; goto identifikator; identifikator : operator ; 16.4. Vneshnie opredeleniya programma: vneshnee_opredelenie vneshnee_opredelenie programma vneshnee_opredelenie: opredelenie_funkcii opredelenie_dannyh opredelenie_funkcii: specifikator_tipa opisatel'_funk- neob cii telo_funkcii opisatel'_funkcii: opisatel' (spisok_parametrov) neob spisok_parametrov: idetifikator identifikator , spisok_parametrov telo_funkcii: spisok_opisanij_tipa operator_funkcii operator_funkcii: {spisok opisanij spisok_operatorov} neob -81- opredelenie dannyh: extern specifikator_tipa spi- neob neob sok inicializiruemyh opisatelej; neob static specifikator tipa spisok neob neob inicializiruemyh opisatelej; neob 16.5. Preprocessor #define identifikator stroka_leksem #define identifikator(identifika- tor,...,identifikator) stroka_leksem #undef identifikator #include "imya_fajla" #include <imya_fajla> #if konstantnoe_vyrazhenie #ifdef identifikator #ifndef identifikator #else #endif #line konstanta "imya_fajla" neob  * 17. Primery programm na Si Primer 1: funkcii fgets i fputs (sm. razdel "Standart- naya biblioteka vvoda/vyvoda. Vvod/vyvod strok"). -82- #include <stdio.h> char *fgets(s,n,iop) /*vzyat'<=n simvolov*/ char *s; /* iz iop */ int n; register FILE *iop; { register int c; register char *cs; cs = s; while(--n>0&&(c=getc(iop)) !=EOF) if ((*cs++ = c)=='\n') break; *cs = '\0'; return((c==EOF && cs==s) ? NULL : s); } fputs(s,iop) /*pomestit' stroku s v */ register char *s; /* fajl iop */ register FILE *iop; { register int c; while (c = *s++) putc(c,iop); } Primer 2. Programma dlya razdeleniya odnogo bol'shogo fajla na neskol'ko chastej tak, chtoby kazhdaya chast' nachinalas' so stroki .sh 1 ... -83- #include <stdio.h> #define NEWH ".sh 1" /*Priznak razdeleniya*/ /* Translyaciya: cc -o ds ds.c Zapusk: ds otkuda kudapref kudasuff rezul'tat: ds a pref suff perepisyvaet fajl a v fajly pref00.suff, pref01.suff, ... */ main (ac,av) char **av; { int nfile=0; /* Poryadkovyj nomer fajla*/ char str[512]; /* Bufer dlya stroki*/ if(ac != 4) { fprintf(stderr, "Nevernoe chislo argumentov0); exit(1); } /* freopen analogichno fopen, no izmenyaet ukazannyj opisatel' fajla, a ne sozdaet novyj. Zdes' my pereopredelyaem stdin */ if(!freopen(av[1],"r",stdin)) { fprintf(stderr, "Ne mogu otkryt':%s0,av[1]); exit(2); } /* Pereopredelili fajl stand. vyvoda */ of(av[2],nfile,av[3]); while( gets(str)) { /* strncmp(s1,s2,l) sravnivaet dve stroki i vozvrashchaet 0, esli pervye l simvolov sovpadayut */ if(strncmp(str,NEWH,strlen(NEWH))== 0) { fclose(fp); nfile++; /* |to prosto informacionnoe soobshchenie */ fprintf(stderr, "Nachalo chasti %d0,nfile); fp = of(av[2],nfile,av[3]); } puts(str); if(ferror(stdout)) { -84- fprintf(stderr, "Osh zapisi v fajl nomer %.2d0,nfile); exit(4); } } exit (0); } /* |ta funkciya sozdaet imya fajla iz treh chastej i otkryvaet ego kak standartnyj vyvod */ of(s1,n,s2) char *s1,*s2; { register FILE *f; char buf[100]; /* sprintf vozvrashchaet svoj pervyj argument */ if(( f = freopen( sprintf(buf,"%s%02d.%s",s1,n,s2) ,"w",stdout))== NULL) { fprintf(stderr, "Ne mogu otkryt' fajl:%s0,buf); exit(4); } return; } -85- SODERZHANIE ''ANNOTACIYA'' ................... 2 1. VVEDENIE .......................................... 1 2. SINTAKSICHESKAYA NOTACIYA ............................ 3 2.1. Klyuchevye slova .................................. 3 2.2. Konstanty ....................................... 4 2.2.1. Celye konstanty ............................... 4 2.2.2. Dlinnye (long) konstanty ...................... 4 2.2.3. Simvol'nye konstanty .......................... 4 2.2.4. Veshchestvennye konstanty ........................ 5 2.3. Stroki .......................................... 5 2.4. Harakteristiki apparatnyh sredstv ............... 6 3. OB'EKTY YAZYKA SI .................................. 6 3.1. Interpretaciya identifikatorov ................... 6 3.2. Ob容kty i l_znacheniya ............................ 8 3.3. Preobrazovaniya .................................. 8 3.3.1. Simvoly i celye ............................... 8 3.3.2. Tipy float i double ........................... 9 3.3.3. Veshchestvennye i celochislennye velichiny ......... 9 3.3.4. Ukazateli i celye ............................. 9 3.3.5. Celoe bez znaka ............................... 9 3.3.6. Arifmeticheskie preobrazovaniya ................. 10 4. VYRAZHENIYA ......................................... 10 4.1. Pervichnye vyrazheniya ............................. 11 4.2. Unarnye operacii ................................ 13 4.3. Mul'tiplikativnye operacii ...................... 14 4.4. Additivnye operacii ............................. 15 4.5. Operacii sdviga ................................. 16 4.6. Operacii otnosheniya .............................. 16 4.7. Operacii ravenstva .............................. 17 4.8. Pobitovaya operaciya 'i' .......................... 17 4.9. Pobitovaya operaciya isklyuchayushchego 'ili' ........... 17 4.10. Pobitovaya operaciya vklyuchayushchego 'ili' ............ 17 4.11. Logicheskaya operaciya 'i' ......................... 18 4.12. Operaciya logicheskogo 'ili' ...................... 18 4.13. Uslovnaya operaciya ............................... 18 4.14. Operaciya prisvaivaniya ........................... 19 4.15. Prisvaivanie struktury .......................... 20 4.16. Operaciya 'zapyataya' .............................. 20 4.17. Starshinstvo i poryadok vychisleniya. ............... 20 5. OPISANIYA .......................................... 22 5.1. Specifikatory klassa pamyati ..................... 22 5.2. Specifikatory tipa .............................. 23 5.3. Opisateli ....................................... 24 5.4. Smysl opisatelej ................................ 24 -86- 5.5. Opisanie struktur i ob容dinenij ................. 26 5.6. Perechislimyj tip ................................ 29 5.7. Inicializaciya ................................... 30 5.8. Imena tipov ..................................... 32 5.9. Opisatel' typedef ............................... 33 6. OPERATORY ......................................... 34 6.1. Operatornoe vyrazhenie ........................... 34 6.2. Sostavnoj operator (ili blok) ................... 34 6.3. Uslovnye operatory .............................. 35 6.4. Operator while .................................. 35 6.5. Operator do ..................................... 35 6.6. Operator for .................................... 35 6.7. Operator switch ................................. 36 6.8. Operator break .................................. 37 6.9. Operator continue ............................... 37 6.10. Operator vozvrata ............................... 38 6.11. Operator goto ................................... 38 6.12. Pomechennyj operator ............................. 38 6.13. Pustoj operator ................................. 38 7. VNESHNIE OPREDELENIYA ............................... 39 7.1. Vneshnee opredelenie funkcii ..................... 39 7.2. Vneshnie opredeleniya dannyh ...................... 40 8. OBLASTX DEJSTVIYA IDENTIFIKATOROV .................. 40 8.1. Leksicheskaya oblast' dejstviya .................... 41 8.2. Oblast' dejstviya vneshnih identifikatorov ........ 42 8.3. Neyavnye opisaniya ................................ 42 9. PREPROCESSOR YAZYKA 'SI' ........................... 43 9.1. Zamena leksem ................................... 43 9.2. Vklyuchenie fajlov ................................ 44 9.3. Uslovnaya kompilyaciya ............................. 45 9.4. Komanda #line ................................... 45 10. DOPOLNITELXNAYA INFORMACIYA O TIPAH ................. 46 10.1. Struktury i ob容dineniya ......................... 46 10.2. Funkcii ......................................... 47 10.3. Massivy, ukazateli i indeksaciya ................. 47 10.4. YAvnye preobrazovaniya ukazatelej ................. 48 11. KONSTANTNYE VYRAZHENIYA ............................. 49 12. SOOBRAZHENIYA O PERENOSIMOSTI ....................... 49 12.1. Anahronizmy ..................................... 51 13. STANDARTNAYA BIBLIOTEKA VVODA I VYVODA ............. 51 13.1. Obrashchenie k standartnoj biblioteke .............. 52 13.2. Standartnyj vvod i vyvod ........................ 52 13.3. Formatnyj vyvod - funkciya printf ................ 53 13.4. Formatnyj vvod - funkciya scanf .................. 55 13.5. Formatnoe preobrazovanie v pamyati ............... 58 -87- 13.6. Dostup k fajlam ................................. 59 13.7. Obrabotka oshibok - stderr i exit .............. 61 13.8. Vvod i vyvod strok .............................. 62 13.9. Funkciya ungetc .................................. 62 13.10.Raznye standartnye funkcii ...................... 62 13.10.1.Upravlenie pamyat'yu ............................ 62 13.10.2.Standartnye funkcii yazyka Si .................. 63 14. VZAIMODEJSTVIE S OPERACIONNOJ SISTEMOJ ............ 63 14.1. Podgotovka programm na Si v OS DEMOS ............ 64 14.2. Dostup k argumentam komandy ..................... 64 15. INTERFEJS SISTEMY DEMOS ........................... 66 15.1. Vvod/vyvod ...................................... 66 15.1.1. Deskriptory fajlov ............................ 66 15.1.2. Nizkourovnevyj vvod/vyvod. .................... 67 15.1.3. Otkrytie, sozdanie, zakrytie i udalenie ....... 68 15.1.4. Proizvol'nyj dostup - lseek ................... 69 15.2. Upravlenie processami ........................... 70 15.2.1. Funkciya system ................................ 71 15.2.2. Vyzov programmy na nizkom urovne - execl ...... 71 15.2.3. Porozhdenie novogo processa - fork ............. 71 15.2.4. Kanal mezhprocessnoj svyazi ..................... 73 15.3. Signaly i preryvaniya ............................ 74 16. Svodka sintaksicheskih pravil ...................... 76 16.1. Vyrazheniya ....................................... 76 16.2. Opisaniya ........................................ 78 16.3. Operatory ....................................... 80 16.4. Vneshnie opredeleniya ............................. 81 16.5. Preprocessor .................................... 82 17. Primery programm na Si ............................ 82 -88-