Verifikator programm na yazyke Si LINT Proizvodstvenno-vnedrencheskij kooperativ "I N T E R F E J S" Dialogovaya Edinaya Mobil'naya Operacionnaya Sistema Demos/P 2.1 Verifikator programm na yazyke Si LINT Moskva 1988 ANNOTACIYA Dokument soderzhit opisanie primenniya verifikatora prog- ramm na yazyke Si lint. Opisana realizaciya programmy lint. VVEDENIE Komanda lint privodit k vypolneniyu programmy lint, kotoraya analiziruet ishodnye teksty Si-programm, vyyavlyaya ryad oshibok i dvusmyslennostej. Po sravneniyu s Si-kompilyatorami programma lint osushchestvlyaet bolee strogij kontrol' za pravi- lami soglasovaniya tipov. Ona mozhet takzhe byt' ispol'zovana dlya proverki ryada ogranichenij, nakladyvaemyh na perenosimye programmy, t.e. ogranichenij, obespechivayushchih svobodnoe ispol'zovanie na razlichnyh mashinah i razlichnyh operacionnyh sistemah. Drugoj vozmozhnost'yu programmy lint yavlyaetsya obna- ruzhenie ryada zakonnyh, no neekonomnyh ili potencial'no oshi- bochnyh konstrukcij. Programma lint mozhet obrabatyvat' nes- kol'ko zadannyh vhodnyh fajlov i bibliotek i proveryat' ih na sovmestimost'. Razdelenie funkcij mezhdu lint i Si-kompilyatorami imeet kak istoricheskie, tak i prakticheskie osnovaniya. Kompilyatory bystro i effektivno perevodyat Si-programmy v ispolnyaemye fajly. |to stalo vozmozhnym otchasti blagodarya tomu, chto kom- pilyatory ne osushchestvlyayut slozhnyh proverok soglasovaniya tipov, osobenno dlya razdel'no kompiliruemyh programm. Prog- ramma lint provodit bolee global'nyj i netoroplivyj analiz programmy, obrashchaya znachitel'no bol'shee vnimanie na voprosy perenosimosti. V etom dokumente obsuzhdaetsya ispol'zovanie programmy lint, daetsya kratkij obzor ee realizacii, a takzhe predlaga- yutsya rekomendacii po napisaniyu mashinno-nezavisimyh Si- programm. 1. Vyzov programmy Predpolozhim, chto imeyutsya dva ishodnyh fajla na yazyke Si file1.c, file2.c, kompiliruemye obychnym obrazom i zagruzhae- mye vmeste. Togda komanda lint file1.c file2.c porozhdaet soobshcheniya, opisyvayushchie nesovmestimye i neeffektiv- nye elementy v dannyh programmah. Programma lint osushchestv- lyaet bolee stroguyu proverku pravil soglasovaniya tipov yazyka Si, chem Si-kompilyatory (chto ob®yasnyaetsya istoricheskimi i prakticheskimi prichinami). Komanda lint -p file1.c file2.c privodit k vydache, v dopolnenie k ukazannym vyshe, soobshchenij, otnosyashchihsya k perenosimosti programm na drugie operacionnye sistemy i mashiny. Zamena flaga -p na -h vyzovet poyavlenie soobshcheniya o razlichnyh neeffektivnyh i mogushchih privodit' k oshibkam - 3 - konstrukciyah, kotorye, strogo govorya, ne yavlyayutsya oshiboch- nymi. Zadanie -hp privodit k vydache vseh vysheupomyanutyh soobshchenij. V neskol'kih sleduyushchih razdelah opisyvayutsya osnovnye soobshcheniya, stat'ya zavershaetsya razdelami, v kotoryh obsuzhda- yutsya voprosy realizacii i dayutsya nekotorye rekomendacii po napisaniyu perenosimyh Si-programm. V prilozhenii privoditsya perechen' klyuchej komandy lint. 2. Nekotorye zamechaniya Mozhet okazat'sya, chto mnogie fakty, neobhodimye prog- ramme lint, nevozmozhno obnaruzhit'. Naprimer, vopros o tom, proizojdet li kogda-libo v nekotoroj programme obrashchenie k nekotoroj konkretnoj funkcii, mozhet zaviset' ot vhodnyh dan- nyh. Reshenie voprosa o tom, budet li kogda-libo vyzvana funkciya exit, ekvivalentno znamenitoj "probleme ostanova", kotoraya yavlyaetsya rekursivno nerazreshimoj. Vsledstvie etogo, bol'shinstvo algoritmov programmy lint osnovano na kompromissnom reshenii. Esli nekotoraya funkciya nikogda ne byla upomyanuta, to ona i ne mozhet byt' vyzvana. Esli zhe nekotoraya funkciya upomyanuta, to programma lint schi- taet, chto ona mozhet byt' vyzvana. I hotya eto uslovie ne vsegda obyazatel'no, prakticheski ono vpolne opravdano. Programma lint staraetsya vydavat' informaciyu s vysokoj stepen'yu sootvetstviya. Soobshcheniya tipa "hhh mozhet byt' oshib- koj" legki dlya generacii, odnako oni priemlemy tol'ko v tom sluchae, esli oni raskryvayut dostatochno bol'shoj procent istinnyh oshibok. Esli zhe dolya istinnyh oshibok slishkom mala, k podobnym soobshcheniyam teryaetsya doverie i oni lish' zagromozh- dayut vyhodnye soobshcheniya, zatrudnyaya etim analiz dejstvitel'no vazhnyh soobshchenij. Imeya vse eto v vidu, rassmotrim teper' bolee podrobno klassy soobshchenij, vydavaemyh programmoj lint. 3. Neispol'zovannye peremennye i funkcii Po mere sozdaniya i razvitiya nekotorogo nabora programm, nekotorye ranee ispol'zuemye peremennye i argumenty funkcij mogut okazat'sya nenuzhnymi. Neredko sluchaetsya, chto vneshnie peremennye ili dazhe celye funkcii, perestayut byt' neobhodi- mymi no poka eshche ne udalyayutsya iz ishodnogo teksta. Podobnye "oshibki" mogut zatrudnit' ponimanie i izmenenie programm. Vmeste s tem, informaciya o takih neispol'zuemyh peremennyh i funkciyah mozhet inogda okazat'sya poleznoj dlya obnaruzheniya oshibok: ved' esli nekotoraya funkciya vypolnyaet neobhodimuyu rabotu, no nikogda ne vyzyvaetsya, znachit chto-to ne v poryadke! - 4 - Programma lint soobshchaet o takih peremennyh i funkciyah - opisannyh, no ne upomyanutyh kakim-libo inym sposobom. Isk- lyuchenie sostavlyayut peremennye, ob®yavlennye s pomoshch'yu yavnogo operatora extern, no na kotorye ne byli proizvedeny ssylki; tak, operator extern float sin(); ne vyzovet nikakogo komentariya, esli identifikator sin nigde ne byl ispol'zovan. Zametim, chto eto soglasuetsya s semanti- koj kompilyatora yazyka Si. Odnako, v nekotoryh sluchayah eti neispol'zovannye vneshnie peremennye mogut predstavlyat' inte- res; oni mogut byt' obnaruzheny posredstvom ukazaniya flaga -x pri vyzove lint. Nekotorye metodiki programmirovaniya trebuyut, chtoby celyj ryad funkcij byl sostavlen s odinakovym naborom argu- mentov, pri etom zachastuyu nekotorye iz etih argumentov oka- zyvayutsya neispol'zovannymi vo mnogih vyzovah. Klyuch -v poz- volyaet podavlyat' pechat' soobshchenij o neispol'zuemyh argumen- tah. Pri ukazanii dannogo klyucha soobshcheniya o neispol'zuemyh argumentah ne vydayutsya, za isklyucheniem teh argumentov, koto- rye ne ispol'zuyutsya i, v to zhe vremya, ob®yavleny kak regist- rovye; takuyu situaciyu mozhno rassmatrivat' kak neproizvodi- tel'noe rashodovanie mashinnyh registrov, kotoroe mozhno pre- dotvratit'. Sushchestvuet sluchaj, kogda informaciya o neispol'zuemyh ili o neopredelennyh peremennyh skoree meshaet, chem pomogaet. On imeet mesto pri primenenii lint k nekotorym, no ne vsem, fajlam iz nabora fajlov, kotorye dolzhny zagruzhat'sya sov- mestno. V etom sluchae mnogie opredelennye funkcii i pere- mennye mogut ne ispol'zovat'sya i, naprotiv, mogut ispol'zo- vat'sya funkcii i peremennye, opredelennye v drugom meste. Dlya podavleniya vydachi etih lozhnyh soobshchenij ispol'zuetsya flag -u. 4. Informaciya ob inicializacii i ispol'zovanii peremennyh Programma lint delaet popytki obnaruzheniya sluchaev ispol'zovaniya peremennyh do prisvaivaniya im nachal'nyh znache- nij. Sdelat' eto ochen' ne legko; mnogie sootvetstvuyushchie algoritmy rashoduyut znachitel'noe kolichestvo vremeni i pamyati i, vse zhe, inogda vydayut soobshcheniya o sovershenno pravil'nyh programmah. Programma lint obnaruzhivaet lokal'nye peremen- nye (iz klassov avtomaticheskoj i registrovoj pamyati), pervoe ispol'zovanie kotoryh poyavlyaetsya vo vhodnom fajle ran'she, chem pervnachal'noe prisvaivanie etim peremennym. Programma polagaet, chto vzyatie adresa peremennoj predstavlyaet ee ispol'zovanie, togda kak dejstvitel'noe ispol'zovanie etoj peremennoj mozhet proizojti v lyuboj moment i zaviset' ot dan- nyh. - 5 - Takoe ogranichenie fizicheskim poyavleniem peremennyh v fajle delaet sootvetstvuyushchij algoritm bystrym i legko reali- zuemym, poskol'ku pri etom net neobhodimosti proslezhivat' fakticheskij potok upravleniya. |to oznachaet, chto lint mozhet vydavat' soobshcheniya o programmah, kotorye yavlyayutsya pravil'- nymi, no kotorye sledovalo by schitat' plohimi po stilisti- cheskim osobennostyam (naprimer, soderzhat po krajnej mere dva operatora goto). Poskol'ku staticheskie i vneshnie peremennye inicializiruyutsya znacheniem nul', to ne mozhet byt' poluchena nikakaya osmyslennaya informaciya ob ih ispol'zovanii. Vmeste s tem algoritm pravil'no obrabatyvaet inicializirovannye avtomaticheskie peremennye, a takzhe peremennye, ispol'zuemye v vyrazheniyah, v kotoryh im snachala prisvaivayutsya znacheniya. Informaciya ob inicializacii i ispol'zovanii pozvolyaet takzhe obnaruzhit' te lokal'nye peremennye, kotorym prisvaiva- yutsya nachal'nye znacheniya, no kotorye nikogda ne ispol'zuyutsya. |to chasto yavlyaetsya istochnikom neeffektivnoj obrabotki, a mozhet okazat'sya i priznakom nalichiya oshibok. 5. Potok upravleniya Programma lint delaet popytki obnaruzhit' nedostigaemyh uchastkov v obrabatyvaemyh programmah. Ona soobshchaet o nali- chii nepomechennyh operatorov, neposredstvenno sleduyushchih za operatorami goto, break, continue, ili return. Delaetsya takzhe popytka obnaruzhit' cikly, iz kotoryh nikogda ne prois- hodit vyhod po koncu tela cikla; pri etom obnaruzhivayutsya special'nye sluchai ispol'zovaniya beskonechnyh ciklov while(1) i for(;;). Programma lint soobshchaet takzhe o ciklah, v koto- rye nevozmozhno vojti cherez ih zagolovok; takie cikly vstre- chayutsya vo mnogih pravil'nyh programmah, chto v luchshem sluchae svidetel'stvuet o plohom stile ih napisaniya, a v hudshem - ob oshibkah. Sleduet otmetit', chto algoritm proverki potoka upravle- niya programmy lint imeet znachitel'noe "slepoe pyatno": net vozmozhnosti obnaruzheniya funkcij, kotorye vyzyvayutsya, no ne vozvrashchayut upravlenie v vyzyvayushchuyu programmu. Tak, vyzov exit mozhet sluzhit' prichinoj nedostizhimosti nekotoroj chasti programmy, chto ne obnaruzhivaetsya programmoj lint. Naibolee ser'ezno eto skazyvaetsya na opredelenii vozvrashchaemyh znache- nij funkcij (sm.sleduyushchij razdel). Imeetsya odin vid nedostigaemogo operatora, ne vyzyvayu- shchego obychno soobshchenij lint: eto - nedostigaemyj operator break. Zametim, chto programmy, poluchennye s pomoshch'yu yacc[2] i, osobenno, lex[3], mogut vklyuchat' bukval'no sotni nedosti- gaemyh operatorov break. Ispol'zovanie flaga -O v Si- kompilyatore privodit k ustraneniyu neeffektivnosti rezul'ti- ruyushchego ob®ektnogo koda. Takim obrazom, eti nedostigaemye operatory ne igrayut bol'shoj roli, i obychno pol'zovatel' nichego ne mozhet s nimi podelat'. T.o. soobshcheniya o nih - 6 - tol'ko by zagromozhdali vydachu programmy lint. Esli eti soobshcheniya vse zhe zhelatel'ny, sleduet vyzyvat' lint s klyuchom -b. 6. Znacheniya funkcij Inogda funkcii vozvrashchayut znacheniya, kotorye nikogda ne ispol'zuyutsya; inogda programmy nekorrektno ispol'zuyut "zna- cheniya" funkcij, kotorye ne byli vozvrashcheny. Programma lint razreshaet etu problemu neskol'kimi sposobami. Na lokal'nom urovne, vnutri nekotorogo opredeleniya funkcii, odnovremennoe poyavlenie operatorov return(vyrazhenie); i return; sluzhit povodom dlya trevogi; programma lint vydaet soobshchenie function name contains ruturn(e) and return" ("funkciya s imenem name soderzhit return(vyrazhenie) i return"). Pri etom naibolee ser'eznuyu trudnost' vyzyvaet sluchaj, kogda vozvra- shchaemoe znachenie zavisit ot potoka upravleniya, kotoryj dosti- gaet konca opredeleniya funkcii. |to mozhet byt' prodemonst- rirovano na prostom primere: f(a){ if(a) return(3); g } Zametim, chto esli a lozhno, to funkciya f vyzyvaet funkciyu g i zatem vozvrashchaet upravlenie, ne opredeliv nikakogo vozvrashcha- emogo znacheniya; eto vyzovet soobshchenie programmy lint. Esli zhe funkciya g, podobno exit, ne vozvrashchaet upravleniya, soob- shchenie vse zhe budet porozhdeno, dazhe esli v dejstvitel'nosti vse verno. S pomoshch'yu etoj vozmozhnosti mozhno obnaruzhit' mnogie potencial'no ser'eznye oshibki; ona zhe neset otvetstvennost' za znachitel'nuyu chast' "shumovyh" soobshchenij, vydavaemyh prog- rammoj lint. Na global'nom urovne programma lint ulavlivaet sluchai, kogda nekotoraya funkciya vozvrashchaet znachenie, kotoroe, odnako, inogda (ili nikogda) ne ispol'zuetsya. Esli eto zna- chenie ne ispol'zuetsya nikogda, mozhno predpolozhit' nalichie neeffektivnogo opredeleniya etoj funkcii. Esli vozvrashchaemoe znachenie inogda ne ispol'zuetsya, to eto mozhet svidetel'stvo- vat' o plohom stile napisaniya programmy (naprimer, ob otsutstvii proverok uslovij poyavleniya oshibok). - 7 - Protivopolozhnyj sluchaj, kogda v kachestve znacheniya funk- cii ispol'zuetsya znachenie, kotoroe dannaya funkciya ne vozvra- shchala, takzhe fiksiruetsya. |ta problema dostatochno ser'ezna. Kak ni udivitel'no, dannaya oshibka neskol'ko raz byla obnaru- zhena v "rabotayushchih" programmah; prosto registr, v kotoryj funkciya vozvratila nuzhnoe znachenie, okazalsya zanyat. Programma lint osushchestvlyaet bolee strogij kontrol' za pravilami soglasovaniya tipov v yazyke Si, chem kompilyatory. Dopolnitel'nye proverki zatragivayut chetyre osnovnye oblasti: opredelennye binarnye operacii, predpolagayushchie prisvaivaniya, operacii vydeleniya chlenov struktur, sootvetstvie opredeleniya funkcij i ih ispol'zovaniya i ispol'zovanie perechislenij. Sushchestvuet nekotoroe chislo operacij, predpolagayushchih sootvetstvie tipov operandov. Takim svojstvom obladayut prisvaivaniya, uslovnaya operaciya (?:) i operacii otnosheniya. V etih operaciyah tipy char, short, int, long, unsigned,float i double mogut byt' proizvol'no smeshany. Tipy ukazatelej dolzhny tshchatel'no soglasovyvat'sya, pri etom, razumeetsya, mas- sivy elementov tipa h mogut smeshivat'sya s ukazatelyami na tip h. Pravila kontrolya tipov trebuyut takzhe, chtoby v obrashcheniyah k strukture levyj operand ->&gt; byl ukazatelem na strukturu, a levyj operand v operacii . (tochka) byl strukturoj i pravyj operand etih operacij byl chlenom struktury, k kotoromu obra- shchaetsya levyj operand. Analogichnyj kontrol' delaetsya i dlya obrashchenij k ob®edineniyam. Strogie pravila nakladyvayutsya na soglasovanie argumen- tov funkcij i soglasovanie vozvrashchaemyh znachenij. Tipy float i double svobodno soglasuyutsya, ravno kak tipy char, short, int i unsigned. Krome togo, ukazateli mogut soglaso- vyvat'sya s sootvetstvuyushchimi massivami. Za isklyucheniem uka- zannyh, vse fakticheskie argumenty dolzhny soglasovyvat'sya po tipu s sootvetstvuyushchimi ob®yavlennymi argumentami. Dlya perechislenij proveryaetsya, chtoby peremennye ili chleny perechislenij ne smeshivalis' s drugimi tipami ili dru- gimi perechisleniyami; oni mogut tol'ko ispol'zovat' v kachestve operacij =, ==, !=, argumenty funkcij i vozvrashchae- mye znacheniya. 7. Izmeneniya tipov Vozmozhnost' izmeneniya tipov v yazyke Si byla shiroko vve- dena v kachestve sredstva polucheniya bolee perenosimyh prog- ramm. Pust' imeetsya prisvaivanie p=1; gde p - ukazatel' na simvoly. Programma lint vpolne obosno- vanno vydast predosteregayushchee soobshchenie. Teper' rassmotrim prisvaivanie - 8 - p = (char*) 1; v kotorom operaciya perevoda tipa byla ispol'zovana dlya pre- obrazovaniya celogo v ukazatel' na simvoly. Ochevidno, prog- rammist imel ser'eznoe osnovanie sdelat' eto i yasno vyrazil svoi namereniya. Poetomu predstavlyaetsya slishkom surovym so storony programmy lint, esli ona budet prodolzhat' vydavat' soobshcheniya ob etom. S drugoj storony, pri perenose dannoj programmy na druguyu mashinu k nej sleduet otnestis' s osto- rozhnost'yu. Flag -c upravlyaet pechat'yu kommentariev ob izme- nenii tipov. Esli flag -c vklyuchen, perevody tipov vyzyvayut vydachu predosteregayushchih soobshchenij, v protivnom sluchae vse dopustimye perevody tipov ne vyzyvayut vydachi kommentiruyushchih soobshchenij, kakim by strannym ni kazalos' dannoe smeshenie tipov. 8. Ispol'zovanie simvolov, narushayushchee perenosimost'. V mashinah tipa SM-1420 simvoly yavlyayutsya velichinami so znakom, v diapazone ot -128 do 127. V bol'shinstve drugih realizacij yazyka Si simvoly prinimayut tol'ko polozhitel'nye znacheniya. Poetomu lint signaliziruet o nekotoryh sravneniyah i prisvaivaniyah kak o nedopustimyh ili neperenosimyh. Nap- rimer, fragment char c; ... if ((c=getchar())<0)... budet rabotat' na SM-1420, no privedet k oshibke na mashinah, v kotoryh simvoly prinimayut tol'ko polozhitel'nye znacheniya. Pravil'noe reshenie zaklyuchaetsya v ob®yavlenii s celym chislom, tak kak funkciya getchar budet vozvrashchat' celye znacheniya. Vo vsyakom sluchae programma lint vyvedet soobshchenie "nonportable character comparison" ("neperenosimoe simvol'noe sravne- nie"). Podobnaya situaciya voznikaet i s polyami bitov; pri vypolnenii prisvaivaniya polyu bitov postoyannogo znacheniya, dannoe pole mozhet okazat'sya slishkom malym dlya hraneniya etogo znacheniya. |to osobenno verno, poskol'ku na nekotoryh mashi- nah polya bitov rassmatrivayutsya kak velichiny so znakom. Mozhno dolgo lomat' golovu nad tem, pochemu dvuhbitovoe pole, ob®yavlennoe kak int, ne mozhet hranit' znachenie 3; eta trud- nost' ustranyaetsya, esli pole bitov ob®yavlyaetsya s tipom unsigned. 9. Prisvaivanie celym tipa int znachenij tipa long Oshibki mogut voznikat' v rezul'tate prisvaivanij veli- chin tipa long peremennym tipa int, pri kotoryh proishodit poterya tochnosti. Takaya situaciya mozhet imet' mesto v prog- rammah, ne polnost'yu preobrazovannyh dlya ispol'zovaniya opre- delenij tipa typedef. Pri izmenenii nekotoroj typedef - peremennoj iz int v long, programma mozhet prekratit' rabotu, - 9 - poskol'ku nekotorye promezhutochnye rezul'taty mogut prisvai- vat'sya peremennym tipa int, chto privodit k potere tochnosti. Poskol'ku imeetsya ryad razumnyh situacij, kogda neobhodimo prisvaivanie velichin tipa long peremennym tipa int, to fik- saciya takih prisvaivanij proizvoditsya tol'ko pri zadanii flaga -a. 10. Strannye konstrukcii Programma lint obnaruzhivaet nekotorye sovershenno pra- vil'nye, no neskol'ko strannye konstrukcii. Sushchestvuet nadezhda, chto soobshcheniya o takih konstrukciyah pobuzhdayut k napisaniyu bolee yasnyh i kachestvennyh programm i mogut dazhe ukazyvat' na oshibki. Vklyuchenie podobnyh proverok osushchestv- lyaetsya s pomoshch'yu flaga -h. Tak naprimer, v operatore *p++ operaciya * ne privodit ni k kakim dejstviyam. po etomu povodu lint vydaet soobshchenie "null effect" ("nulevoj effekt"). Fragment programmy unsigned x ; if (x<0) ... yavno neskol'ko stranen, poskol'ku dannoe sravnenie nikogda ne budet istinnym. Podobno etomu, sravnenie if (x>0) ... ekvivalentno sravneniyu if (x!=0) chto mozhet i ne byt' zhelaemym dejstviem. V takih sluchayah vydaetsya soobshchenie lint: "degenerate unsigned comparison" ("vyrozhdennoe sravnenie velichin tipa unsigned"). Esli ispol'zuetsya vyrazhenie if (1!=0)... to programma lint napechataet "constant in conditional con- text" ("konstanta v uslovnom kontekste"), poskol'ku sravne- nie 1 s 0 daet postoyannyj rezul'tat. Programma lint analiziruet takzhe konstrukcii, vklyuchayu- shchie operacii s raznym prioritetom. Oshibki, proishodyashchie iz-za nepravil'nogo ponimaniya poryadka predshestvovaniya opera- cij, mogut byt' zamaskirovany vvedeniem probelov i formati- rovaniem, chto delaet ih obnaruzhenie ves'ma trudnym. Napri- mer, operatory if (x & 077 ==0) ... ili x<<2 + 40 - 10 - veroyatno vypolnyayut ne to, chto trebovalos'. Luchshim razreshe- niem podobnyh sluchaev yavlyaetsya zaklyuchenie takih vyrazhenij v kruglye skobki, o chem lint i napominaet v sootvetstvuyushchem soobshchenii. Nakonec, pri ispol'zovanii flaga -h programma lint soobshchaet o peremennyh, pereopredelennyh vo vnutrennih blokah takim sposobom, chto eto protivorechit ih ispol'zovaniyu v ob®emlyushchih blokah. I hotya takaya situaciya yavlyaetsya dopusti- moj, ona, po mneniyu mnogih svidetel'stvuet o plohom stile napisaniya programmy i obychno ne yavlyayas' neobhodimoj, zachas- tuyu govorit o nalichii oshibki. 11. O rannih versiyah yazyka Sushchestvuet neskol'ko form starogo sintaksisa, primene- nie kotoryh oficial'no ne odobryaetsya. Oni delyatsya na dva klassa - operacii prisvaivaniya i inicializaciya. Primenenie staryh form operacij prisvaivaniya (naprimer, =+, =-, ...)mozhet porodit' dvusmyslennye vyrazheniya, podobnye a=-i; chto mozhet traktovat'sya libo kak a =- 1; libo kak a = -1; Podobnaya situaciya osobenno zaputyvaet v tom sluchae, esli takaya dvusmyslennost' voznikaet v rezul'tate makropodsta- novki. Otmetim, chto v poslednej versii yazyka podobnye ope- racii (+=, -= i t.d.), kotoryj yavlyayutsya bolee predpochtitel'- nymi, ne porozhdayut takih dvusmyslennostej. S cel'yu pobuzhde- niya udaleniya bolee rannih form programma lint vydaet soobshche- niya i takih staromodnyh operaciyah. Podobnye problemy voznikayut i pri inicializacii. V rannej versii yazyka dopustima konstrukciya int x 1; dlya inicializacii x znacheniem 1. |to takzhe porozhdaet sin- taksicheskie trudnosti: naprimer, ob®yavlenie int x (-1); mozhet pokazyvat'sya pohozhim na nachalo ob®yavleniya funkcii: int x (y) {.... i translyator dolzhen analizirovat' bol'shoj fragment vhodnogo - 11 - teksta za x dlya togo, chtoby ubedit'sya, chto dejstvitel'no predstavlyaet soboj eto ob®yavlenie. V dannom sluchae, kak i v predydushchem, problema uslozhnyaetsya, esli inicializiruyushchaya konstrukciya vklyuchaet nekotoryj makros. v nastoyashchee vremya sintaksis trebuet vvedeniya znaka ravenstva mezhdu peremennoj i inicializatorom: int x= -1; etim polnost'yu isklyuchaetsya vozniknovenie kakoj-libo sintak- sicheskoj dvusmyslennosti. 12. Vyravnivanie ukazatelej Nekotorye prisvaivaniya dlya ukazatelej mogut byt' pra- vil'nymi na odnih mashinah, no nevernymi na drugih, chto celi- kom obuslovleno trebovaniyami vyravnivaniya. Naprimer, na SM-1420 dopuskaetsya prisvaivanie celyh ukazatelej ukazatelyam "na tip double", t.k. znacheniya dvojnoj tochnosti mogut nachi- nat'sya s granicy celogo chisla. Na mashine Honeywell 6000 znacheniya dvojnoj tochnosti dolzhny nachinat'sya s granicy chetnyh slov; takim obrazom, ne vse prisvaivaniya takogo tipa budut imet' smysl. Programma lint staraetsya obnaruzhit' sluchai prisvaivaniya ukazatelej drugim ukazatelyam i vydelit' sluchai vozmozhnogo vozniknoveniya problemy vyravnivaniya. V takih situaciyah, esli ukazany flagi -p ili -h, vydaetsya soobshchenie "possible pointer alignment problem" ("vozmozhna oshibka vyravnivaniya ukazatelej"). 13. Mnogokratnye ispol'zovaniya i pobochnye effekty V slozhnyh vyrazheniyah nailuchshij poryadok vychisleniya pod- vyrazhenij mozhet byt' v znachitel'noj stepeni mashinno- zavisimym. Naprimer, na mashinah (tipa SM-1420), v kotoryh stek obrabatyvaetsya v obratnom napravlenii, argumenty funk- cii, veroyatno, luchshe vychislit' sprava nalevo. V mashinah s pryamoj obrabotkoj steka bolee privlekatel'nym yavlyaetsya porya- dok sleva napravo. Vyzovy funkcij, ispol'zuemye v kachestve argumentov drugih funkcij, mogut traktovat'sya podobno obych- nym argumentom, a mogut obrabatyvat'sya i drugim obrazom. Podobnye momenty voznikayut i dlya drugih operacij, obladayushchih pobochnymi effektami, naprimer, dlya operacij prisvaivaniya i dlya operacij uvelicheniya i umen'sheniya. CHtoby izbezhat' chrezmernoj poteri effektivnosti yazyka Si na konkretnoj mashine, vybor poryadka vychisleniya slozhnyh vyra- zhenij v yazyke Si ne fiksiruetsya i vozlagaetsya na lokal'nyj (orientirovannyj na konkretnuyu mashinu) kompilyator. Vsledst- vie etogo razlichnye kompilyatory yazyka Si imeyut znachitel'nye razlichiya v smysle poryadka, v kotorom vychislyayutsya slozhnye vyrazheniya. V chastnosti, esli nekotoraya peremennaya izmenya- etsya v rezul'tate pobochnogo effekta i eta peremennaya eshche gde-nibud' v tom zhe samom vyrazhenii, to rezul'tat vychislenij - 12 - ne budet tochno opredelen. Programma lint proveryaet special'nyj sluchaj, kogda izmenyaetsya prostaya skalyarnaya peremennaya. Naprimer, operator a[i]=b[i++] ; vyzovet poyavlenie soobshcheniya warning: i evaluation order undefined (predosterezhenie: neopredelen poryadok vychisleniya i). 14. Realizaciyach Programma lint realizuetsya s pomoshch'yu dvuh programm i drajvera. Pervoj programmoj yavlyaetsya versiya perenosimogo Si-kompilyatora[4,5] kotoraya sluzhit osnovoj dlya kompilyatorov yazyka Si dlya mashin IBM-370, IHoneywell 6000 i Interdata 8/32. Dannyj kompilyator vypolnyaet leksicheskij i sintaksi- cheskij analiz vhodnogo teksta, sozdaet i podderzhivaet tab- licu simvolov i stroit derev'ya vyrazhenij. Vmesto zapisi nekotorogo promezhutochnogo fajla, pereda- vaemogo generatoru koda, kak eto delaetsya drugimi kompilyato- rami, programma lint vyrabatyvaet promezhutochnyj fajl, koto- ryj sostoit iz strok teksta v kode ASCII. Kazhdaya stroka soderzhit imya vneshnej peremennoj, kodirovku konteksta, v kotorom eta peremennaya poyavlyaetsya (ispol'zovanie, opredele- nie, ob®yavlenie i t.p.), specifikator tipa, imya ishodnogo fajla i nomer stroki. Informaciya o peremennyh, lokal'nyh po otnosheniyu k funkcii ili fajlu, sobiraetsya s pomoshch'yu dostupa k tablice simvolov i issledovaniya derev'ev vyrazhenij. Kommentarii ob obnaruzhennyh "lokal'nyh" somnitel'nyh mestah vydayutsya po mere obnaruzheniya. Informaciya o vneshnih imenah nakaplivaetsya v promezhutochnom fajle. Posle togo, kak budut sobrany vse opisaniya iz ishodnyh fajlov i bibliotek, promezhutochnyj fajl sortiruetsya dlya ob®edineniya vmeste vsej sobrannoj informacii o kazhdoj konkretnoj vneshnej peremennoj. Vtoraya, dovol'no malen'kaya, programma chitaet zatem stroki iz promezhutochnogo fajla i sravnivaet vse opredeleniya, ob®yavle- niya i ispol'zovaniya na sovmestimost'. Programma-drajver upravlyaet ukazannym processom, a takzhe neset otvetstvennost' za to, chtoby zadannye klyuchi byli izvestny oboim prohodam programmy lint. 15. Perenosimost' V razlichnyh realizaciyah yazyka Si dopuskalis' otstuple- niya ot standarta yazyka sistemy UNIX. Tem ne menee mnogie Si-programmy byli s nebol'shimi usiliyami uspeshno pereneseny - 13 - na razlichnye ustanovki. V dannom razdele opisyvayutsya neko- torye razlichiya realizacij Si, a takzhe obsuzhdayutsya poleznye svojstva programmy lint. Neinicializirovannye vneshnie peremennye obrabatyvayutsya po-raznomu v razlichnyh realizaciyah yazyka Si. Predpolozhim, chto imeyutsya dva fajla, kazhdyj iz kotoryh soderzhit vne kakoj-libo funkcii ob®yavlenie bez inicializacii (naprimer, int a;). Redaktor svzej DEMOS pri obrabotke etih ob®yavlenij vydelit dlya a tol'ko odno slovo pamyati. V ramkah nekotoryh realizacij eto nevozmozhno (po razlichnym prichinam, kotorye trudno schest' razumnymi!), i kazhdoe takoe ob®yavlenie vlechet zavedenie svoego vneshnego imeni. V moment zagruzki eto pri- vedet k fatal'nomu konfliktu. Esli programma lint budet vyzvana s flagom -c, to takie mnogokratnye ob®yavleniya budut vyyavleny. Analogichnye trudnosti voznikayut pri predstavlenii vnesh- nih imen v ob®ektnom fajle. V sisteme DEMOS vneshnie imena imeyut sem' znachashchih simvolov, prichem uchityvaetsya razlichie verhnego i nizhnego registrov. V sistemah ES |VM chislo zna- chashchih simvolov ravno vos'mi, odnako razlichie registrov igno- riruetsya. Dannoe obstoyatel'stvo mozhet porozhdat' situacii, kogda programma, rabotayushchaya v DEMOS ne sobiraetsya v drugih sistemah. Ispol'zovanie flaga -p vyzyvaet preobrazovanie vseh imen vneshnih peremennyh k odnomu registru i usekaet ih do shesti simvolov, predusmatrivaya pri etom analiz "hudshego sluchaya". Nekotorye trudnosti voznikayut i pri obrabotke simvolov: simvoly v DEMOS predstavlyayutsya vosem'yu bitami v kode KOI-8, v OS ES ispol'zuetsya vos'mibitnyh kod DKOI. Krome togo, stroki simvolov raspolagayutsya ot starshej k mladshej bitovoj pozicii ("sleva napravo") v sistemah ES, i ot mladshej k starshej pozicii ("sprava nalevo") na SM-1420. |to oznachaet, chto fragment programmy, vypolnyayushchij postroenie strok ne iz simvol'nyh konstant, ili ispol'zuyushchij simvoly v kachestve indeksov massivov, dolzhen proveryat'sya ochen' vnimatel'no. lint ne mozhet sushchestvenno pomoch' v dannoj situacii, za isk- lyucheniem ukazaniya simvol'nyh konstant, sostoyashchih iz neskol'- kih simvolov. Estestvenno, razmery slova v raznyh mashinah mogut raz- lichat'sya. Odnako, eto vyzyvaet men'she zatrudnenij, chem mozhno bylo by ozhidat', po krajnej mere, pri perenose s 16- bitnoj mashiny na 32-bitnuyu. Po vsej veroyatnosti, osnovnye problemy voznikayut pri sdvigah i maskirovanii. V nastoyashchee vremya yazyk Si obespechivaet obrabotku bitovyh polej, chto poz- volyaet pisat' znachitel'nuyu chast' takih kodov s vysokoj ste- pen'yu perenosimosti. CHasto perenosimost' takih programm mozhet byt' rasshirena putem nebol'shoj perestrojki stilya prog- rammirovaniya. Mnogie iz nesovmestimostej yavlyayutsya, po- vidimomu, sledstviem zapisej tipa - 14 - x &= 0177700 dlya obnuleniya shesti mladshih bitov x. Buduchi udovletvori- tel'noj dlya SM-1420, takaya zapis' privedet k tyazheloj oshibke na ES |VM. ZHelaemyj effekt mozhet byt' poluchen pri ispol'zo- vanii kontsrukcii: x &= 077; kotoraya vypolnyaetsya pravil'no na vseh rassmatrivaemyh mashi- nah. Operaciya sdviga vpravo yavlyaetsya arifmeticheskim sdvigom na SM-1420 i logicheskim sdvigom na bol'shinstve drugih mashin. Dlya polucheniya logicheskogo sdviga dlya vseh mashin, levyj ope- rand mozhet zadavat'sya v vide celogo bez znaka. Simvoly schi- tayutsya celymi so znakom v SM-1420, no celymi bez znaka v drugih mashinah. Takoe "povedenie" znakovogo bita mozhet byt' spravedlivo rasceneno kak oshibka apparaturoj PDP-11, harak- teristiki kotoroj okazali opredelennoe vliyanie na yazyk Si. Esli by imelsya priemlemyj sposob obnaruzheniya programm, v kotoryh vstrechaetsya ukazannaya trudnost', yazyk Si mog by byt' izmenen. Vo vsyakom sluchae, programma lint zdes' bessil'na. Privedennye vyshe primery mogut sozdat' vpechatlenie, chto problema perenosimosti predstavlyaet bol'she trudnostej, chem eto est' v dejstvitel'nosti. Voznikayushchie zdes' voprosy redko byvayut neulovimymi ili zagadochnymi, po krajnej mere dlya razrabotchika programmy, hotya i mogut inogda potrebovat' opredelennoj raboty po ih ustraneniyu. Znachitel'no bolee ser'eznym prepyatstviem dlya perenosimosti utilit sistemy DEMOS yavlyaetsya nevozmozhnost' imitirovat' sushchestvennye funk- cii sistemy DEMOS na drugih sistemah. Nevozmozhnost' dostupa k simvolu, nahodyashchemusya v proizvol'noj pozicii v tekstovom fajle, ili nevozmozhnost' ustanovleniya mezhprogrammnogo inter- fejsa trebuet znachitel'no bol'shej pererabotki i otladki, chem lyubye razlichiya v kompilyatorah yazyka Si. S drugoj storony, programma lint yavlyaetsya ochen' poleznoj pri perenose operaci- onnoj sistemy DEMOS i svyazannyh s nej programm-utilit na drugie mashiny. 16. Upravlenie vydachej soobshchenij Byvayut sluchai, kogda programmist umnee programmy lint. Tak, mogut byt' veskie prichiny dlya ispol'zovaniya "nedopusti- myh" izmenenij tipa, funkcij s peremennym chislom argumentov i t.d. Bolee togo, kak ukazano vyshe, informaciya o potoke upravleniya, porozhdaemaya lint, chasto imeet "slepye pyatna", chto mozhet vyzvat' sluchajnye lozhnye soobshcheniya o vpolne razum- nyh programmah. Takim obrazom, zhelatel'no imet' nekotorye sposoby svyazi s lint, obychno dlya podavleniya takih lozhnyh soobshchenij. - 15 - Forma, kotoruyu dolzhen imet' takoj mehanizm, ne vpolne yasna. Delo v tom, chto vvedenie, naprimer, novyh klyuchevyh slov potrebovalo by ot sovremennyh i staryh kompilyatorov obespecheniya raspoznavaniya etih slov ili po krajnej mere ih ignorirovaniya. Pri etom voznikayut kak filosofskie, tak i prakticheskie trudnosti, v chastnosti potrebuet izmeneniya sin- taksis novogo preprocessora. V konce bylo resheno, chto ryad slov, nahodyashchihsya vnutri kommentariev, dolzhen raspoznavat'sya programmoj lint. |to potrebovalo minimal'nyh izmenenij v preprocessore: prepro- cessor propuskaet kommentarii v svoj vyhod, a ne udalyaet ih, kak eto delalos' ran'she. Takim obrazom, direktivy lint yavlyayutsya nevidimymi dlya kompilyatorov; effekt etih izmenenij dlya sistem so starymi preprocessorami zaklyuchaetsya tol'ko v tom, chto eti direktivy programmy lint na etih sistemah ne rabotayut. Pervaya direktiva otnositsya k informacii o potoke uprav- leniya: esli kakoj-to uchastok programmy ne mozhet byt' dostig- nut, a programme lint eto ne ochevidno, to ego mozhno ukazat' programme lint s pomoshch'yu direktivy /* NOTREACHED */, pome- shchennoj v podhodyashchej tochke programmy. Podobnym obrazom, esli zhelatel'no otklyuchit' stroguyu proverku tipov v posleduyushchim vyrazhenii, to mozhet byt' ispol'zovana direktiva /* NOSTRICT */ Posle obrabotki etogo vyrazheniya lint vozvratitsya v prezhnee (prinimaemoe po umolchaniyu) sostoyanie. Flag -v mozhet byt' vklyuchen dlya odnoj funkcii s pomoshch'yu direktivy /* ARGUSED */ Soobshcheniya o razlichnom chisle argumentov pri obrashcheniyah k nekotoroj funkcii mogut byt' podavleny direktivoj /* VARARGS */ pomeshchennoj pered opredeleniem dannoj funkcii. V nekotoryh sluchayah zhelatel'no proveryat' neskol'ko pervyh argumentov, ostavlyaya ostal'nye argumenty neproverennymi. |to mozhet byt' ukazano klyuchevym slovom VARARGS, za kotorym sleduet cifra, zadayushchaya chislo argumentov, kotorye dolzhny byt' provereny; tak, /* VARARGS2 */ vyzyvaet proverku lish' pervyh dvuh argumentov. Nakonec, direktiva /* LINTLIBRARY */ - 16 - pomeshchennaya v zagolovke fajla, ukazyvaet, chto dannyj fajl yavlyaetsya fajlom ob®yavleniya biblioteki. |toj teme posvyashchen sleduyushchij razdel. 17. Fajly ob®yavleniya bibliotek Programma lint dopuskaet neskol'ko bibliotechnyh direk- tiv, podobnyh -ly, i proveryaet ishodnye fajly na sovmesti- most' s etimi bibliotekami. |to osushchestvlyaetsya putem dos- tupa v fajly opisaniya bibliotek, imena kotoryh (fajlov) stroyatsya iz bibliotechnyh direktiv. Vse takie fajly nachina- yutsya direktivoj /* LINTLIBRARY */ za kotoroj sleduet seriya pustyh opredelenij funkcij. Kriti- cheskimi chastyami etih opredelenij yavlyayutsya: opredelenie tipa vozvrashchaemogo funkciej znacheniya, vopros - ne vozvrashchaet li pustaya funkciya nekotorogo znacheniya, a takzhe chislo i tipy argumentov funkcii. Dlya ukazaniya osobennostej dannyh bibli- otechnyh funkcij mogut byt' ispol'zovany direktivy VARARGS i ARGUSED. Bibliotechnye fajly lint obrabatyvayutsya pochti v tochnosti tak zhe, chto i obychnye ishodnye fajly. Edinstvennoe razlichie zaklyuchaetsya v tom, chto o funkciyah, opredelennyh v bibliotech- nom fajle, no ne ispol'zovannyh v ishodnom fajle, ne vyda- etsya nikakih soobshchenij. Programma lint ne modeliruet polnyj algoritm poiska v biblioteke, i vydaet predosteregayushchee soobshchenie v sluchae, esli ishodnye fajly soderzhat pereoprede- lenie nekotoroj bibliotechnoj funkcii (eto-osobennost'!). Po umolchaniyu programma lint sveryaet ukazannye ej prog- rammy so standartnym bibliotechnym fajlom, soderzhashchim opisa- nie programm, kotorye obychno zagruzhayutsya pri rabote programm na yazyke Si. Pri zadanii flaga -p proveryaetsya drugoj fajl, soderzhashchij opisanie standartnyh programm biblioteki vvoda/vyvoda, kotorye, kak ozhidaetsya, obladayut perenosi- most'yu na razlichnye mashiny. Dlya podavleniya vseh proverok bibliotek mozhno ispol'zovat' flag -n. 18. Oshibki i t.d. Pri sozdanii programmy lint razrabotchiki vstretilis' so znachitel'nymi trudnostyami, otchasti obuslovlennymi tesnoj svyaz'yu s voprosami stilya programmirovaniya, a otchasti tem, chto pol'zovateli obychno ne uvedomlyayut o situaciyah, v kotoryh programma propuskaet oshibki, o kotoryh ona dolzhna by byla informirovat'. (Interesno, chto v sluchayah, kogda lint oshi- bochno soobshchaet o nesushchestvuyushchih na samom dele oshibkah, prog- rammisty otklikayutsya nemedlenno). - 17 - Dal'nejshee usovershenstvovanie programmy lint mozhno vesti v neskol'kih napravleniyah. Tak, nedostatochno adek- vatna proverka struktur i massivov, nikakih popytok proverki sootvetstviya ob®yavlenij struktur i ob®edinenij v razlichnyh fajlah. YAsno, chto zhelatel'no neskol'ko bolee strogaya pro- verka ispol'zovaniya opredeleniya tipov typedef; odnako vopros o tom, kakoj uroven' kontrolya budet dostatochen i kak dobi- vat'sya etogo - eshche trebuet opredeleniya. Programma lint delit preprocessor s Si-kompilyatorom. |to mozhet okazat'sya blagopriyatnym obstoyatel'stvom dlya sozda- niya special'noj versii preprocessora, ohvatyvayushchego ryad ne vypolnyaemyh v nastoyashchee vremya proverok, takih kak neispol'- zuemye makroopredeleniya, makroargumenty kotoryh imeyut poboch- nye effekty, ili kotorye ne rasshiryayutsya voobshche, ili rasshirya- yutsya bolee chem odin raz i t.d. Central'noj problemoj, svyazannoj s lint, yavlyaetsya upa- kovka sobiraemoj informacii. Imeetsya mnogo klyuchej, sluzhashchih edinstvenno dlya vyklyucheniya ili nebol'shogo izmeneniya teh ili inyh osobennostej obrabotki. Imeetsya tendenciya vklyucheniya eshche bol'shego chisla takih klyuchej. V zaklyuchenie otmetim, chto skladyvaetsya vpechatlenie, chto osnovnaya ideya sozdaniya dvuh programm okazalas' udachnoj. Kompilyator koncentriruetsya na bystrom i tochnom perevode programmnogo teksta v ispolnyaemyj kod, a programma lint zanimaetsya glavnym obrazom voprosami perenosimosti, stilya i effektivnosti. Programma lint mozhet pozvolit' sebe oshi- bat'sya, poskol'ku nekorrektnost' i izlishnij konservatizm, hotya i razdrazhayut, no ne gubitel'ny. Kompilyator mozhet rabo- tat' bystro, poskol'ku on "znaet", chto programma lint v slozhnoj situacii "prikroet ego flangi". Nakonec, program- mist mozhet sosredotochit'sya isklyuchitel'no na takih aspektah processa programmirovaniya, kak opisanie algoritmov i struk- tur dannyh i korrektnosti programmy, a zatem obespechit' s pomoshch'yu lint zhelaemye svojstva universal'nosti t perenosi- mosti. PRILOZHENIE. Spisok imeyushchihsya klyuchej komandy lint V nastoyashchee vremya komanda lint imeet sleduyushchij format: lint [-klyuchi] fajly ... deskriptory-biblioteki... Klyuchami yavlyayutsya: h Osushchestvlyat' evristicheskij kontrol' p Osushchestvlyat' kontrol' perenosimosti - 18 - v Ne vydavat' soobshchenij o neispol'zuemyh argumentah u Ne vydavat' soobshchenij o neispol'zuemyh ili neopredelen- nyh vneshnih peremennyh b Vydavat' soobshcheniya o nedostizhimyh operatorah break x Vydavat' soobshcheniya o neispol'zovannyh ob®yavleniyah vnesh- nih peremennyh a Vydavat' soobshcheniya o prisvaivaniyah znachenij tipa long znacheniyam tipa int