| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428 |
- \chapter{Справочное руководство}
- \label{apx:ref_manual}
- \section{Введение}
- Данное руководство является описанием языка программирования Си, определённого в
- соответствии с проектом, утверждённым в
- \index{American National Standards Institute (ANSI)}%
- ANSI в качестве Американского национального стандарта для информационных систем:
- Язык программирования Си, X3.159--1989 (<<American National Standard for
- Information Systems -- Programming Language C, X3.159--1989>>). Это описание --
- лишь некоторый вариант предлагаемого стандарта, а не сам стандарт, однако мы
- специально заботились о том, чтобы оно было надёжным руководством по языку.
- Настоящий документ в основном следует общей схеме описания, принятой в стандарте
- (публикация которого в свою очередь основывалась на первом издании этой книги),
- однако в организационном плане есть различия. Если не считать отклонений в
- названиях нескольких продукций и отсутствия формальных определений лексем и
- препроцессора, грамматики языка здесь и в стандарте эквивалентны.
- \begin{ApxComment}
- Далее всюду примечания (как и это) набираются с отступом от левого края
- страницы. В основном эти примечания касаются отличий стандарта от версии языка,
- описанной в первом издании этой книги‚ и от последующих нововведений в различных
- компиляторах.
- \end{ApxComment}
- \section{Соглашения о лексике}
- \index{лексика, соглашения}%
- \index{транслируемая компонента}%
- Программа состоит из одной или нескольких \emph{компонент трансляции},
- хранящихся в виде файлов.
- \index{трансляция!фазы}%
- \index{фазы трансляции}%
- Каждая такая компонента проходит ряд фаз трансляции, описанных
- в~\ref{apx:sec:preprocessing}. Начальные фазы осуществляют лексические
- преобразования нижнего уровня, выполняют директивы, задаваемые в программе
- строками, начинающимися со знака \verb|#|, обрабатывают макроопределения и
- получают макрорасширения. По завершению
- препроцессирования~(\ref{apx:sec:preprocessing}) программа представляется в виде
- последовательности лексем.
- \subsection{Лексемы}
- \index{лексема}%
- Существуют шесть классов лексем: идентификаторы, ключевые слова, константы,
- стринговые литералы, операторы и прочие разделители.
- \index{литера!новая-строка \texttt{\textbackslash n}}%
- \index{литеры!пробельные}%
- \index{пробельные литеры}%
- \index{n@\texttt{\textbackslash n}}%
- Пробелы, горизонтальные и вертикальные табуляции, новые-строки,
- переводы-страницы и
- \index{комментарий}%
- комментарии (имеющие общее название <<пробельные литеры>>) рассматриваются
- компилятором только как разделители лексем и в остальном на результат трансляции
- влияния не оказывают.
- \index{отступы в тексте программы}%
- \index{программа!формат}%
- Любая из пробельных литер годится, чтобы отделить друг от друга соседние
- идентификаторы, ключевые слова и константы.
- Если предположить, что входной поток уже до некоторой литеры разбит на лексемы,
- то следующей лексемой будет самый длинный стринг, который вообще может быть
- лексемой.
- \subsection{Комментарий}
- \index{комментарий}%
- Литеры \verb|/*| открывают комментарий, а литеры \verb|*/| закрывают его.
- Комментарии нельзя вкладывать друг в друга, их нельзя помещать внутрь стрингов
- или текстовых литералов.
- \subsection{Идентификаторы}
- \index{идентификатор}%
- \index{переменная!синтаксис имени}%
- \index{синтаксис имён переменных}%
- \index{функция!длина имени}%
- Идентификатор -- последовательность букв и цифр. Первой литерой должна быть
- буква;
- \index{литера!подчёркивания \texttt{\_}}%
- знак подчёркивания \verb|_| считается буквой. Буквы нижнего и верхнего регистров
- различаются.
- \index{длина!имени}%
- \index{длина!переменной}%
- Идентификаторы могут иметь любую длину; для внутренних идентификаторов значимыми
- являются первая 31 литера; в некоторых реализациях принято б\'{o}льшее число
- значимых литер. К внутренним идентификаторам относятся имена макросов и
- \index{имя}%
- все другие имена, не имеющие внешних связей~(\ref{apx:subsec:links}).
- \index{связь!внешняя}%
- На идентификаторы с внешними связями могут накладываться б\'{o}льшие
- ограничения: иногда воспринимаются не более шести первых литер и/или не
- различаются буквы верхнего и нижнего регистров.
- \subsection{Ключевые слова}
- \index{ключевые слова}%
- \index{список!ключевых слов}%
- Следующие идентификаторы зарезервированы в качестве ключевых слов и в другом
- смысле использоваться не могут:
- \smallskip
- {\setlength{\LTleft}{\doubleCodeIndent-\parindent-\tabcolsep}%
- \SetLenVarWithVal{\Quarterlen}{(\linewidth-\LTleft-7\tabcolsep-\doubleCodeIndent+\parindent)/4}%
- \noindent\hspace{\LTleft}\begin{tabular}
- {p{\Quarterlen}p{\Quarterlen}p{\Quarterlen}p{\Quarterlen}}
- \verb|auto| &\verb|double|&\verb|int| &\verb|struct| \\
- \verb|break| &\verb|else| &\verb|long| &\verb|switch| \\
- \verb|case| &\verb|enum| &\verb|register|&\verb|typedef| \\
- \verb|char| &\verb|extern|&\verb|return| &\verb|union| \\
- \verb|const| &\verb|float| &\verb|short| &\verb|unsigned|\\
- \verb|continue|&\verb|for| &\verb|signed| &\verb|void| \\
- \verb|default| &\verb|goto| &\verb|sizeof| &\verb|volatile|\\
- \verb|do| &\verb|if| &\verb|static| &\verb|while|
- \end{tabular}}
- \smallskip
- \noindent%
- \index{asm@\texttt{asm}}%
- \index{fortran@\texttt{fortran}}%
- В некоторых реализациях резервируются также слова \verb|fortran| и \verb|asm|.
- \begin{ApxComment}
- Ключевые слова \verb|const|, \verb|signed| и \verb|volatile| впервые появились в
- стандарте ANSI; \verb|enum| и \verb|void| -- новые по отношению к первому
- изданию, но уже использовались; ранее зарезервированное \verb|entry| нигде не
- использовалось и поэтому более не резервируется.
- \end{ApxComment}
- \subsection{Константы}
- \label{apx:subsec:constants}
- \index{константа}%
- \index{константа!тип}%
- \index{тип!константа}%
- Существует несколько видов констант. Каждая имеет свой тип данных; базовые типы
- рассматриваются в~\ref{apx:subsec:base_types}.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{константа:}
- \textit{целая-константа}
- \textit{литерная-константа}
- \textit{с-плав-точкой-константа}
- \textit{перечислимая-константа}
- \end{ShortGramDecsWithCC}
- \subsubsection{Целые константы}
- \index{целая константа}%
- \index{константа!восьмеричная \texttt{0}\ldots}%
- \index{восьмеричная константа \texttt{0}\ldots}%
- \index{int@\texttt{int}!константа}%
- \index{signed@\texttt{signed}!константа}%
- Целая константа, состоящая из последовательности цифр, воспринимается как
- восьмеричная, если она начинается с \verb|0| (цифры нуль), и как десятичная в
- противном случае. Восьмеричная константа не содержит цифр \verb|8| и \verb|9|.
- \index{константа!шестнадцатеричная \texttt{0x}\ldots}%
- \index{шестнадцатеричная константа \texttt{0x}\ldots}%
- Последовательность цифр, перед которой стоят \verb|0x| или \verb|0X|,
- рассматривается как шестнадцатеричное целое. В шестнадцатеричные цифры включены
- буквы от \verb|a| (или \verb|A|) до \verb|f| (или \verb|F|) со значениями от
- $10$ до $15$.
- %
- % исправлены орфографические ошибки
- % было ``шестнадцатиричное''/''шестнадцатиричные''
- %
- \index{константа!суффикс}%
- \index{суффикс в константе}%
- \index{unsigned@\texttt{unsigned}!константа}%
- \index{unsigned long, константа@\texttt{unsigned long}, константа}%
- Целая константа может быть записана с буквой-суффиксом \verb|u| (или \verb|U|)
- для спецификации её как беззнаковой константы.
- \index{long@\texttt{long}!константа}%
- Она также может быть с буквой-суффиксом \verb|l| (или \verb|L|) для указания,
- что она имеет тип \verb|long|.
- \index{int@\texttt{int}!константа}%
- \index{long@\texttt{long}!константа}%
- \index{signed@\texttt{signed}!константа}%
- \index{unsigned@\texttt{unsigned}!константа}%
- Тип целой константы зависит от её вида, значения и суффикса. (О типах
- см.~\ref{apx:sec:what_identificators_mean}.) Если константа -- десятичная и не
- имеет суффикса, то она принимает первый из следующих типов, который годится для
- представления её значения: \verb|int|, \verb|long int| и
- \verb|unsigned long int|. Восьмеричная или шестнадцатеричная константа без
- суффикса принимает первый возможный из типов \verb|int|, \verb|unsigned int|,
- \verb|long int| и \verb|unsigned long int|. Если константа имеет суффикс
- \verb|u| или \verb|U|, то она принимает первый возможный из типов
- \verb|unsigned int| и \verb|unsigned long int|. Если константа имеет суффикс
- \verb|l| или \verb|L|, то она принимает первый возможный из типов
- \verb|long int| и \verb|unsigned long int|.
- %
- % исправлена орфографическая ошибка
- % было ``шестнадцатиричная''
- %
- \begin{ApxComment}
- Типы целых констант получили существенное развитие в сравнении с первой
- редакцией, в которой большие целые имели просто тип \verb|long|. Суффиксы
- \verb|U| и \verb|u| введены впервые.
- \end{ApxComment}
- \subsubsection{Литерные константы}
- \label{apx:subsubsec:character_constants}
- \index{литера!кавычка \texttt{'}}%
- \index{константа!литерная}%
- \index{char@\texttt{char}!константа}%
- Литерная константа -- последовательность из одной или нескольких литер,
- заключённая в одиночные кавычки (например, \verb|'x'|). Если внутри одиночных
- кавычек расположена одна литера, значением константы является числовое значение
- этой литеры в кодировке, принятой на данной машине. Значение константы с
- несколькими литерами зависит от реализации.
- Литерная константа не может содержать в себе одиночную кавычку <<\verb|'|>> или
- литеру новая-строка;
- \index{эскейп-последовательность}%
- чтобы изобразить их и некоторые другие литеры, могут быть использованы
- эскейп-последовательности:
- {\setlength{\LTleft}{\codeIndent-\tabcolsep}
- \setlength{\LTpre}{\smallskipamount}\setlength{\LTpost}{\smallskipamount}%
- \index{таблица!эскейп-последовательностей}%
- \begin{longtable}{lll}
- новая-строка (\verb|newline|, \verb|linefeed|)%
- \index{литера!новая-строка \texttt{\textbackslash n}}%
- \index{n@\texttt{\textbackslash n}}%
- &\verb|NL (LF)|&\verb|\n|\\
- гориз-таб (\verb|horisontal tab|)%
- \index{t@\texttt{\textbackslash t}}%
- &\verb|HT| &\verb|\t|\\
- верт-таб (\verb|vertical tab|)%
- \index{литера!вертикальная табуляция \texttt{\textbackslash v}}%
- \index{v@\texttt{\textbackslash v}}%
- &\verb|VT| &\verb|\v|\\
- возврат-на-шаг (\verb|backspace|)%
- \index{b (backspace)@\texttt{\textbackslash b} (backspace)}%
- &\verb|BS| &\verb|\b|\\
- возврат-каретки (\verb|carriage return|)%
- \index{литера!возврат каретки \texttt{\textbackslash r}}%
- \index{r@\texttt{\textbackslash r}}%
- &\verb|CR| &\verb|\r|\\
- перевод-страницы (\verb|formfeed|)%
- \index{литера!новая-страница \texttt{\textbackslash f}}%
- \index{f литера новая-страница@\texttt{\textbackslash f} литера новая-страница}%
- &\verb|FF| &\verb|\f|\\
- сигнал-звонок (\verb|audible alert|,\verb|bell|)%
- \index{литера!сигнал-звонок \texttt{\textbackslash a}}%
- \index{a@\texttt{\textbackslash a}}%
- &\verb|BEL| &\verb|\a|\\
- обратная-наклонная-черта (\verb|backslash|)%
- \index{литера!обратная наклонная черта \texttt{\textbackslash\textbackslash}}%
- &\verb|\| &\verb|\\|\\
- знак-вопроса (\verb|question mark|) &\verb|?| &\verb|\?|\\
- одиночная-кавычка (\verb|single quote|)%
- \index{литера!кавычка \texttt{'}}%
- &\verb|'| &\verb|\'|\\
- двойная-кавычка (\verb|double quote|)%
- \index{литера!двойная кавычка \texttt{\char`\"}}%
- &\verb|"| &\verb|\"|\\
- восьмеричный-код (\verb|octal number|)%
- \index{ooo@\texttt{\textbackslash\textit{ooo}}}%
- &\textit{\Verb|ooo|}&\verb|\|\textit{\Verb|ooo|}\\
- шестнадцатеричный-код (\verb|hex number|)%
- \index{xhh шестнадцатеричная эскейп-последовательность@\texttt{\textbackslash x\textit{hh}} шестнадцатеричная эскейп-последовательность}%
- &\textit{\Verb|hh|}&\verb|\x|\textit{\Verb|hh|}\\
- \end{longtable}}
- %
- % исправлена орфографическая ошибка
- % было ``шестнадцатиричный''
- %
- \noindent%
- \index{константа!литерная!восьмеричная \texttt{\textbackslash\textit{ooo}}}%
- \index{эскейп-последовательность!восьмеричная \texttt{\textbackslash\textit{ooo}}}%
- Эскейп-последовательность \verb|\|\textit{\Verb|ooo|} состоит из обратной
- наклонной черты, за которой следуют одна, две или три восьмеричные цифры,
- специфицирующие значение желаемой литеры.
- \index{null-литера, 0@null-литера, \texttt{\textbackslash 0}}%
- Наиболее частым примером такой конструкции является \verb|\0| (за которой не
- следует цифра); она специфицирует null-литеру.
- \index{константа!литерная!шестнадцатеричная \texttt{\textbackslash x\textit{hh}}}%
- \index{эскейп-последовательность!шестнадцатеричная \texttt{\textbackslash x\textit{hh}}}%
- Эскейп-последовательность \verb|\x|\textit{\Verb|hh|} состоит из обратной
- наклонной черты с буквой \verb|x|, за которыми следуют шестнадцатеричные цифры,
- специфицирующие значение желаемой литеры. На количество цифр нет ограничений, но
- результат будет не определён, если значение полученной литеры превысит значение
- самой <<большой>> из допустимых литер. Если в данной реализации тип \verb|char|
- трактуется как число со знаком, то значение и в восьмеричной, и в
- шестнадцатеричной эскейп-последовательности получается при помощи
- \index{знак, размножение}%
- <<размножения знака>>, как если бы выполнялась операция приведения к типу
- \verb|char|. Результат не определён, если за \verb|\| не следует ни одна из
- перечисленных выше литер.
- %
- % исправлены орфографические ошибки
- % было ``шестнадцатиричные'' и ``шестнадцатиричной''
- %
- \index{константа!литерная!из расширенного набора}%
- В некоторых реализациях имеется расширенный набор литер, который не может быть
- охвачен типом \verb|char|. Константа для такого набора пишется с буквой \verb|L|
- впереди (например, \verb|L'x'|) и называется <<широкой>> литерной константой.
- \index{wchar{\_}t@\texttt{wchar{\_}}}%
- Такая константа имеет тип \verb|wchar_t| (целочисленный тип, определённый в
- стандартном головном файле \verb|<stddef.h>|). Как и в случае обычных литерных
- констант, здесь также возможны восьмеричные и шестнадцатеричные
- эскейп-последовательности; результат будет не определён, если специфицированное
- значение превысит тип \verb|wchar_t|.
- %
- % исправлены орфографические ошибки
- % было ``шестнадцатиричные''
- %
- \begin{ApxComment}
- Некоторые из приведённых эскейп-последовательностей новые (шестнадцатеричные в
- частности). Новым является и расширенный тип для литер. Наборам литер, обычно
- используемым в Америке и Западной Европе, подходит тип \verb|char|, а тип
- \verb|wchar_t| был добавлен, главным образом для того, чтобы удовлетворить
- азиатские языки.
- \end{ApxComment}
- %
- % исправлены орфографические ошибки
- % было ``шестнадцатиричные''
- %
- \subsubsection{Константы с плавающей точкой (плавающие константы)}
- \index{константа!с плавающей точкой}%
- \index{константа!суффикс}%
- \index{суффикс в константе}%
- \index{экспонента в записи числа}%
- \index{double@\texttt{double}!константа}%
- \index{E (спецификатор экспоненты)@\texttt{E} (спецификатор экспоненты)}%
- \index{float@\texttt{float}!константа}%
- \index{long double@\texttt{long double}!константа}%
- Плавающая константа состоит из целой части, десятичной точки, дробной части,
- \verb|e| или \verb|E| и целого (возможно, со знаком), представляющего
- экспоненту, и, возможно, типа-суффикса, задаваемого одной из букв: \verb|f|,
- \verb|F|, \verb|l| или \verb|L|. И целая, и дробная часть представляют собой
- последовательность цифр. Либо целая часть, либо дробная часть (но не обе вместе)
- могут отсутствовать; также могут отсутствовать десятичная точка или \verb|E| с
- экспонентой (но не обе одновременно). Тип определяется суффиксом; \verb|F| или
- \verb|f| определяют тип \verb|float|, \verb|L| или \verb|l| -- тип
- \verb|long double|; при отсутствии суффикса подразумевается тип \verb|double|.
- \begin{ApxComment}
- Суффиксы для плавающих констант являются нововведением.
- \end{ApxComment}
- \subsubsection{Перечислимые константы}
- \index{константа!перечисления}%
- \index{перечисление!константа}%
- \index{enum@\texttt{enum}!спецификатор}%
- Идентификаторы, объявленные как элементы
- перечисления~(\ref{apx:subsec:enumerations})‚ являются константами типа
- \verb|int|.
- \subsection{Стринговые литералы}
- \label{apx:subsec:string_literals}
- \index{литера!двойная кавычка \texttt{\char`\"}}%
- \index{константа!стринговая}%
- Стринговый литерал, который также называют стринговой константой, -- это
- последовательность литер, заключённая в двойные кавычки (например,
- \verb|"..."|). Стринг имеет тип <<массив литер>> и память класса
- \verb|static|~(\ref{apx:sec:what_identificators_mean}), которая инициализируется
- заданными литерами. Представляются ли одинаковые стринговые литералы одной
- копией или несколькими, зависит от реализации. Поведение программы, пытающейся
- изменить стринговый литерал, не определено.
- \index{конкатенация!стрингов}%
- \index{стринг!конкатенация}%
- Рядом написанные стринговые литералы объединяются (конкатенируются) в один
- стринг. После любой конкатенации к стрингу добавляется \verb|null|-байт
- (\verb|\0|), что позволяет программе, просматривающей стринг, найти его конец.
- Стринговые литералы не могут содержать в себе новую-строку или двойную кавычку;
- в них нужно использовать те же эскейп-последовательности, что и в литерных
- константах.
- Как и в случае с литерными константами, стринговый литерал с литерами из
- расширенного набора должен начинаться с буквы \verb|L| (например,
- \verb|L"..."|). Стринговый литерал из расширенного набора имеет тип <<массив из
- \verb|wchar_t|>>. Конкатенация обычных и <<расширенных>> стринговых литералов
- друг с другом не определена.
- \begin{ApxComment}
- То, что стринговые литералы не обязательно представляются разными копиями,
- запрет на их модификацию, а также конкатенация соседних стринговых литералов
- являются нововведениями ANSI-стандарта. <<Расширенные>> стринговые литералы
- также объявлены впервые.
- \end{ApxComment}
- \section{Нотация синтаксиса}
- \index{нотация синтаксиса}%
- В нотации синтаксиса, используемой в этом руководстве, синтаксические понятия
- набираются курсивом, а слова и литеры, воспринимаемые буквально, обычным
- шрифтом. Альтернативные конструкции обычно перечисляются в столбик (каждая
- альтернатива на отдельной строке); в редких случаях длинные списки небольших по
- размеру альтернатив располагаются в одной строке, помеченной словами
- <<один из>>. Необязательный терминальный или нетерминальный символ снабжается
- индексом <<\textit{необ}>>. Так, запись
- \begin{ShortGramDecsWithCC}{\\\[\]}
- { \textit[выражение]\textsubscript[\textit[необ]] }
- \end{ShortGramDecsWithCC}
- \noindent обозначает выражение, заключённое в фигурные скобки, которое в общем
- случае может отсутствовать. Полный перечень синтаксических конструкций приведён
- в~\ref{apx:sec:grammar}.
- \begin{ApxComment}
- В отличие от грамматики, данной в первом издании этой книги, приведённая здесь
- грамматика старшинство и порядок выполнения операций в выражениях описывает
- явно.
- \end{ApxComment}
- \section{Что обозначают идентификаторы}
- \label{apx:sec:what_identificators_mean}
- \index{перечислитель}%
- Существует ряд вещей, на которые ссылаются при помощи идентификаторов, или имён;
- это -- функции; теги структур, объединений и перечислений; члены структур или
- объединений; \verb|typedef|-имена и объекты.
- \index{объект}%
- \index{переменная}%
- Объектом (называемым иногда переменной) является часть памяти, интерпретация
- которой зависит от двух главных характеристик: \emph{класса памяти} и её
- \emph{типа}. Класс памяти сообщает о времени жизни памяти, связанной с
- идентифицируемым объектом; тип определяет, какого рода значения находятся в
- объекте.
- \index{область действия}%
- С любым именем ассоциируется своя область действия (т.е. тот участок программы,
- где это имя <<видимо>>) и
- \index{связь}%
- \index{связь!внутренняя}%
- атрибут связи, определяющий, ссылается ли это имя в другом файле на тот же самый
- объект или функцию. Область действия и атрибут связи обсуждаются
- в~\ref{apx:sec:scope}.
- \subsection{Класс памяти}
- \index{память!автоматическая}%
- \index{память!статическая}%
- \index{память!класс}%
- \index{переменная!автоматическая}%
- Существуют два класса памяти: автоматический и статический. Несколько ключевых
- слов в совокупности с контекстом деклараций объектов специфицируют класс памяти
- для этих объектов. Автоматические объекты локализованы в
- блоке~(\ref{apx:subsec:composit_instruction})‚ они <<исчезают>> при выходе из
- него. Декларация, заданная внутри блока, если в ней отсутствует спецификация
- класса памяти или указан спецификатор \verb|auto|, создаёт автоматический
- объект. Объект, помеченный в декларации словом \verb|register|, является
- автоматическим и размещается по возможности в регистре машины.
- \index{переменная!внешняя}%
- \index{static-переменные@\texttt{static}-переменные!внешние}%
- \index{static-переменные@\texttt{static}-переменные!внутренние}%
- Статические объекты могут быть локализованы в блоке или располагаться вне
- блоков, но в обоих случаях их значения сохраняются после выхода из блока (или
- функции) до повторного в него входа. Внутри блока (в том числе и в блоке,
- образующем тело функции) статические объекты в декларациях помечаются словом
- \verb|static|. Объекты, декларируемые вне всех блоков на одном уровне с
- определениями функций, всегда статические. При помощи ключевого слова
- \verb|static| их можно локализовать в пределах транслируемой компоненты (в этом
- случае они получают атрибут \emph{внутренней связи}),
- \index{связь!внешняя}%
- и они становятся глобальными для всей программы, если опустить явное указание
- класса памяти или использовать ключевое слово \verb|extern| (в этом случае они
- получают атрибут \emph{внешней связи}).
- \subsection{Базовые типы}
- \label{apx:subsec:base_types}
- \index{типы!базовые}%
- Существует несколько базовых типов. Стандартный головной файл \verb|<limits.h>|‚
- описанный в приложении~\ref{apx:stdlib}, определяет самое большое и самое малое
- значения для каждого типа в данной конкретной реализации. В
- приложении~\ref{apx:stdlib} приведены минимально возможные величины.
- \index{char@\texttt{char}!тип}%
- Размер объектов, декларируемых как литеры, позволяет хранить любую литеру из
- набора литер, принятого в машине. Если объект типа \verb|char| действительно
- хранит литеру из данного набора, то его значением является код этой литеры, т.е.
- некоторое неотрицательное целое. Переменные типа \verb|char| могут хранить и
- другие значения, но тогда диапазон их значений и особенно вопрос о том, знаковые
- эти значения или беззнаковые, зависит от реализации.
- \index{литера!знаковая}%
- \index{литера!беззнаковая}%
- Беззнаковые литеры, декларируемые при помощи слов \verb|unsigned char|, имеют ту
- же разрядность, что и обычные литеры, но представляют неотрицательные значения;
- при помощи слов \verb|signed char| можно явно декларировать литеры со знаком,
- которые занимают столько же места, как и обычные литеры.
- \begin{ApxComment}
- Тип \verb|unsigned char| не упоминался в первой редакции, но всеми
- использовался. Тип \verb|signed char| -- новый.
- \end{ApxComment}
- \index{типы!целочисленные}%
- \index{целочисленные типы}%
- \index{int@\texttt{int}!тип}%
- \index{long@\texttt{long}!тип}%
- \index{short@\texttt{short}}%
- \index{signed@\texttt{signed}!тип}%
- Помимо \verb|char| среди целочисленных типов могут быть целые трёх размеров:
- \verb|short int|, \verb|int| и \verb|long int|. Обычные \verb|int|-объекты
- имеют естественный размер, принятый в архитектуре данной машины, другие размеры
- предназначены для специальных нужд. Более длинные целые по крайней мере
- покрывают все значения более коротких целых, однако в некоторых реализациях
- обычные целые могут быть эквивалентны коротким (\verb|short|) или длинным
- (\verb|long|) целым. Все типы \verb|int| представляют значения со знаком, если
- не оговорено противное.
- \index{unsigned@\texttt{unsigned}!тип}%
- Для беззнаковых целых в декларациях используется ключевое слово \verb|unsigned|.
- Такие целые подчиняются арифметике по модулю $2^n$, где $n$ -- число бит в
- представлении числа, и, следовательно, в арифметике с беззнаковыми целыми
- никогда не бывает переполнения. Множество неотрицательных значений, которые
- могут храниться в знаковых объектах, является подмножеством значений, которые
- могут храниться в соответствующих беззнаковых объектах; знаковое и беззнаковое
- представления каждого такого значения совпадают.
- \index{типы!плавающие}%
- Любые два из плавающих типов:
- \index{float@\texttt{float}!тип}%
- с одинарной точностью (\verb|float|),
- \index{double@\texttt{double}!тип}%
- с двойной точностью (\verb|double|) и
- \index{long double@\texttt{long double}!тип}%
- с повышенной точностью (\verb|long double|) могут быть синонимами, но каждый
- следующий тип этого списка должен по крайней мере обеспечивать точность
- предыдущего.
- \begin{ApxComment}
- \verb|long double| -- новый тип. В первой редакции синонимом для \verb|double|
- был \verb|long float|, теперь последний изъят из обращения.
- \end{ApxComment}
- \index{перечисление!тип}%
- \emph{Перечисления} -- единственные в своём роде типы, которым даётся полный
- перечень значений; с каждым перечислением связывается множество именованных
- констант~(\ref{apx:subsec:enumerations}). Перечисления ведут себя наподобие
- целых, но компилятор обычно выдаёт предупреждающее сообщение, если объекту
- некоторого перечислимого типа присваивается нечто, отличное от его константы,
- или выражение не этого перечислимого типа.
- \index{типы!арифметические}%
- Поскольку объекты перечислимых типов можно рассматривать как числа, перечисление
- относят к \emph{арифметическому} типу. Типы \verb|char| и \verb|int| всех
- размеров, каждый из которых может быть со знаком или без знака, а также
- перечислимые типы называют \emph{целочисленными}. Типы \verb|float|,
- \verb|double| и \verb|long double| называются \emph{плавающими}.
- \index{void@\texttt{void}!тип}%
- Тип \verb|void| специфицирует пустое множество значений. Он используется как
- <<тип возвращаемого функцией значения>> в том случае, когда она не генерирует
- никакого результирующего значения.
- \subsection{Выводимые типы}
- \index{выводимые типы}%
- \index{типы!выводимые}%
- Помимо базовых типов существует практически бесконечный класс выводимых типов,
- которые формируются из уже существующих и которые описывают следующие
- конструкции:
- \begin{itemize}
- \item \emph{массивы} объектов заданного типа;
- \item \emph{функции}, возвращающие объекты заданного типа;
- \item \emph{указатели} на объекты заданного типа;
- \item \emph{структуры}, содержащие последовательность объектов, возможно,
- различных заданных типов;
- \item \emph{объединения}, каждое из которых может содержать один из нескольких
- объектов различных заданных типов.
- \end{itemize}
- В общем случае приведённые методы конструирования объектов могут применяться
- рекурсивно.
- \subsection{Квалификаторы типов}
- \label{apx:subsec:type_qualifiers}
- Тип объекта может снабжаться квалификатором.
- \index{const@\texttt{const}}%
- Декларация объекта с квалификатором \verb|const| указывает на то, что его
- значение далее не будет изменяться;
- \index{volatile@\texttt{volatile}}%
- объявляя объект как \verb|volatile| (изменчивый, непостоянный (\textit{англ.}))
- мы указываем на его особые свойства в отношении оптимизации, выполняемой
- компилятором. Ни один из квалификаторов не влияет на диапазоны значений и
- арифметические свойства объектов. Квалификаторы обсуждаются
- в~\ref{apx:subsec:type_specifiers}.
- \section{Объекты и l-значения}
- \label{apx:sec:objects_and_lvalues}
- \index{объект}%
- \emph{Объект} -- это некоторая именованная область памяти;
- \index{l-значение}%
- \emph{l-значение} -- выражение, ссылающееся на объект. Очевидным примером
- l-значения является идентификатор с соответствующим типом и классом памяти.
- Существуют операции, порождающие l-значения. Например, если \verb|E| --
- выражение типа указатель, то \verb|*E| есть выражение для l-значения,
- ссылающегося на объект, на который указывает \verb|E|. Термин <<l-значение>>
- произошёл от записи присваивания \verb|E1 = E2|, в которой левый (left -- левый
- (\textit{англ.}), отсюда и буква l) операнд \verb|E1| должен быть выражением
- l-значения. Описывая каждый оператор, мы сообщаем, ожидает ли он l-значения в
- качестве операндов и выдаёт ли l-значение в качестве результата.
- \section{Преобразования}
- \label{apx:sec:type_conversion}
- \index{оператор!приведения к типу|(}%
- \index{преобразование|(}%
- \index{приведение к типу|(}%
- \index{преобразование!оператором приведения}%
- \index{тип!правила преобразования|(}%
- Некоторые операторы в зависимости от своих операндов могут вызывать
- преобразование их значений из одного типа в другой. В этом разделе объясняется,
- что следует ожидать от таких преобразований.
- В~\ref{apx:subsec:arifmetic_conversion} формулируются правила, по которым
- выполняются преобразования для большинства обычных операторов. Эти правила могут
- уточняться при рассмотрении каждого отдельного оператора.
- \subsection{Повышение целочисленного типа}
- \label{apx:subsec:integral_promotion}
- \index{переполнение|(}%
- \index{повышение!целочисленного типа}%
- \index{преобразование!литера -- целое}%
- \index{целочисленное повышение}%
- Объект перечислимого типа, литера, короткое целое, целое в поле бит -- все они
- со знаком или без могут использоваться в выражении там, где возможно применение
- целого. Если тип \verb|int| позволяет <<охватить>> все значения исходного типа
- операнда, то операнд приводится к \verb|int|, в противном случае он приводится к
- \verb|unsigned int|. Эта процедура называется \emph{повышением целочисленности}.
- \subsection{Целочисленные преобразования}
- \index{преобразование!целое -- литера}%
- Любое целое приводится к некоторому заданному беззнаковому типу путём поиска
- конгруэнтного (т.е. имеющего то же двоичное представление) наименьшего
- неотрицательного значения и взятия его по модулю $n_{max}+1$, где $n_{max}$ --
- наибольшее число в этом беззнаковом типе. Для двоичного представления в
- дополнительном коде это означает либо выбрасывание лишних старших разрядов, если
- беззнаковый тип <<\'{y}же>> исходного типа, либо заполнение недостающих старших
- разрядов нулями (для значения без знака) или размноженным знаком (для значения
- со знаком), если беззнаковый тип <<шире>> исходного.
- %
- % исправлена орфографическая ошибка
- % в оригинале было ``конгруентного''
- %
- В результате приведения любого целого к знаковому типу преобразуемое значение не
- меняется, если оно представимо в новом типе, в противном случае результат
- зависит от реализации.
- \subsection{Целые и плавающие}
- \index{обрезание!значения с плавающей точкой}%
- \index{преобразование!плавающее -- целое}%
- \index{преобразование!целое -- плавающее}%
- При преобразовании из плавающего типа в целый дробная часть значения
- отбрасывается; если полученное при этом значение нельзя представить в заданном
- целом типе, то результат не определён. В частности, не определён результат
- преобразования отрицательных плавающих значений в беззнаковые целые.
- Если значение преобразуется из целого в величину с плавающей точкой и она
- находится в допустимом диапазоне, но представляется в новом типе неточно, то
- результатом будет одно из двух значений нового типа, ближайшего к исходному.
- Если результат выходит за границы диапазона допустимых значений, поведение
- программы не определено.
- \subsection{Плавающие типы}
- \index{преобразование!\texttt{double} -- \texttt{float}}%
- \index{преобразование!\texttt{float} -- \texttt{double}}%
- При преобразовании из плавающего типа с меньшей точностью в плавающий тип с
- большей точностью значение не изменяется. Если, наоборот, переход осуществляется
- от большей точности к меньшей и значение остаётся в допустимых пределах нового
- типа, то результатом будет одно из двух ближайших значений нового типа. Если
- результат выходит за границы диапазона допустимых значений, поведение программы
- не определено.
- \subsection{Арифметические преобразования}
- \label{apx:subsec:arifmetic_conversion}
- \index{преобразование!обычное арифметическое}%
- Во многих операциях преобразование типов операндов и определение типа результата
- осуществляются по одним и тем же правилам. Они состоят в том, что операнды
- приводятся к некоторому общему типу, который также является и типом результата.
- Эти правила называются \emph{обычными арифметическими преобразованиями}.
- \begin{itemize}
- \item Если какой-либо из операндов имеет тип \verb|long double|, то другой
- приводится к \verb|long double|.
- \item В противном случае, если какой-либо из операндов имеет тип \verb|double|,
- то другой приводится к \verb|double|.
- \item В противном случае, если какой-либо из операндов имеет тип \verb|float|,
- то другой приводится к \verb|float|.
- \item В противном случае для обоих операндов осуществляется повышение
- целочисленности; затем, если один из операндов имеет тип
- \verb|unsigned long int|, то и другой преобразуется в \verb|unsigned long int|.
- \item В противном случае, если один из операндов принадлежит типу
- \verb|long int|, а другой -- \verb|unsigned int|, то результат зависит от того,
- покрывает ли \verb|long int| все значения \verb|unsigned int|, и если это так,
- то \verb|unsigned int| приводится к \verb|long int|, если нет, то оба операнда
- преобразуются в \verb|unsigned long int|.
- \item В противном случае, если один из операндов имеет тип \verb|long int|, то
- другой приводится к \verb|long int|.
- \item В противном случае, если один из операндов -- \verb|unsigned int|, то
- другой приводится к \verb|unsigned int|.
- \item В противном случае оба операнда имеют тип \verb|int|.
- \end{itemize}
- \begin{ApxComment}
- Здесь два изменения. Во-первых, арифметика с \verb|float|-операндами теперь
- может быть с одинарной точностью, а не только с двойной; в первой редакции вся
- плавающая арифметика была с двойной точностью. Во-вторых, более короткий
- беззнаковый тип в комбинации с более длинным знаковым типом не распространяет
- свойство беззнаковости на тип результата; в первой редакции беззнаковый тип
- всегда доминировал. Новые правила немного сложнее, но до некоторой степени
- уменьшают вероятность появления неожиданных эффектов в комбинациях знаковых и
- беззнаковых величин. При сравнении беззнакового выражения со знаковым того же
- размера всё же может возникнуть неожиданный результат.
- \end{ApxComment}
- \subsection{Указатели и целые}
- \label{apx:subsec:pointers_and_integers}
- \index{вычитание из указателя}%
- \index{преобразование!указателя}%
- \index{преобразование!указатель -- целое|(}%
- \index{преобразование!целое -- указатель}%
- \index{указатели!арифметика с}%
- \index{указатели!вычитание}%
- \index{указатель!преобразование}%
- К указателю можно прибавлять (и вычитать из него) выражение целочисленного типа;
- последнее в этом случае подвергается преобразованию, описанному
- в~\ref{apx:subsec:additive_operators} при рассмотрении оператора сложения.
- К двум указателям на объекты одного типа, принадлежащие одному массиву, может
- применяться операция вычитания; результат приводится к целому посредством
- преобразования, описанного в~\ref{apx:subsec:additive_operators} при
- рассмотрении оператора вычитания.
- \index{указатель!пустой}%
- \index{null-указатель}%
- Целочисленное константное выражение со значением $0$ или оно же, но приведённое
- к типу \verb|void *|, может быть преобразовано в указатель любого типа
- операторами приведения, присваивания и сравнения. Результатом будет
- \verb|null|-указатель, который равен любому другому \verb|null|-указателю того
- же типа, но не равен никакому указателю, ссылающемуся на реальный объект или
- функцию.
- Допускаются и другие преобразования для указателей, но в связи с ними возникает
- проблема зависимости результата от реализации. Эти преобразования должны быть
- специфицированы явным оператором преобразования типа или оператором
- приведения~(\ref{apx:subsec:conversion_operator}~и~\ref{apx:subsec:names_of_types}).
- Указатель можно привести к достаточно большому для его хранения целочисленному
- типу; требуемый размер зависит от реализации. Функция преобразования также
- зависит от реализации.
- Объект целочисленного типа можно явно преобразовать в указатель. Если целое
- получено из указателя и имеет достаточно большой размер, это преобразование даст
- тот же указатель; в противном случае результат зависит от реализации.
- \index{переполнение|)}%
- Указатель на один тип можно преобразовать в указатель на другой тип.
- \index{выравнивание!ограничения по}%
- Если исходный указатель ссылается на объект, должным образом не выровненный по
- границам слов памяти, то в результате может получиться указатель, адресующий к
- <<исключённому>> фрагменту. Если требования на выравнивание у нового типа меньше
- или совпадают с требованиями на выравнивание первоначального типа, то
- гарантируется, что преобразование указателя в другой тип и обратно его не
- изменит; понятие <<выравнивание>> реализационно-зависимо, однако в любой
- реализации объекты типа \verb|char| предъявляют минимальные требования на
- выравнивание. Как описано в~\ref{apx:subsec:pointers_to_void}‚ указатель может
- также преобразовываться в \verb|void *| и обратно, значение указателя при этом
- не изменяется.
- Указатель может быть преобразован в другой указатель того же типа с добавлением
- или удалением
- квалификаторов~(\ref{apx:subsec:type_qualifiers},~\ref{apx:subsec:type_specifiers})
- того типа объекта, на который этот указатель ссылается. Новый указатель,
- полученный добавлением квалификатора, имеет то же значение, но с дополнительными
- ограничениями, внесёнными новыми квалификаторами. Операция по удалению
- квалификатора у объекта приводит к тому, что восстанавливается действие его
- начальных квалификаторов, заданных в декларации этого объекта.
- Наконец, указатель на функцию может быть преобразован в указатель на функцию
- другого типа. Вызов функции по преобразованному указателю зависит от реализации;
- однако, если указатель ещё раз преобразовать к его исходному типу, результат
- будет идентичен вызову по первоначальному указателю.
- \index{преобразование!указатель -- целое|)}%
- \subsection{Тип
- \texorpdfstring{\protect\Verb|void|}{void}}
- \index{void@\texttt{void}!тип}%
- Значение (несуществующее) объекта типа \verb|void| никак нельзя использовать,
- его также нельзя явно или неявно привести к типу отличному от \verb|void|.
- Поскольку выражение типа \verb|void| обозначает отсутствие значения, его можно
- применять только там, где не требуется значения; например, в качестве
- выражения-инструкции~(\ref{apx:subsec:statement-expression}) или левого операнда
- у оператора <<запятая>>~(\ref{apx:subsec:operator_comma}).
- Выражение можно привести к типу \verb|void| операцией приведения типа. Например,
- применительно к вызову функции, используемому в роли выражения-инструкции,
- операция приведения к \verb|void| явным образом подчёркивает тот факт, что
- результат функции отбрасывается.
- \begin{ApxComment}
- Тип \verb|void| не фигурировал в первом издании этой книги, однако за прошедшее
- время стал общеупотребительным.
- \end{ApxComment}
- \subsection{Указатели на
- \texorpdfstring{\protect\Verb|void|}{void}}
- \label{apx:subsec:pointers_to_void}
- \index{преобразование!указателя}%
- \index{указатель!преобразование}%
- \index{указатель!void *@\texttt{void *}}%
- \index{void *, указатель@\texttt{void *}, указатель}%
- Любой указатель на объект можно привести к типу \verb|void *| без потери
- информации. Если результат подвергнуть обратному преобразованию, то мы получим
- прежний указатель. В отличие от преобразований указатель-в-указатель
- (рассмотренных в~\ref{apx:subsec:pointers_and_integers})‚ которые требуют явных
- операторов приведения к типу, в присваиваниях и сравнениях указатель любого типа
- может выступать в паре с указателем типа \verb|void *| без каких-либо
- предварительных преобразований типа.
- \begin{ApxComment}
- Такая интерпретация указателей \verb|void *| -- новая; ранее роль обобщённого
- указателя отводилась указателю типа \verb|char *|. Стандарт ANSI официально
- разрешает использование указателей \verb|void *| совместно с указателями других
- типов в присваиваниях и сравнениях; в иных комбинациях указателей стандарт
- требует явных преобразований типа.
- \end{ApxComment}
- \index{тип!правила преобразования|)}%
- \index{приведение к типу|)}%
- \index{преобразование|)}%
- \index{оператор!приведения к типу|)}%
- \section{Выражения}
- \index{выражение|(}%
- \index{вычисление, порядок}%
- \index{оператор!приоритет}%
- \index{операторы!ассоциативные}%
- \index{порядок!вычислений}%
- \index{приоритеты операторов}%
- Приоритеты описываемых операторов имеют тот же порядок, что и подразделы данного
- параграфа (от высших к низшим). Например, для оператора \verb|+|, описанного
- в~\ref{apx:subsec:additive_operators}, термин <<операнды>> означает <<выражения,
- определённые
- в~\ref{apx:subsec:generation_of_pointer}--\ref{apx:subsec:multiplication_operators}>>.
- В каждом подразделе описываются операторы, имеющие одинаковый приоритет, и
- указывается их ассоциативность (левая или правая). Приоритеты и ассоциативность
- всех операторов отражены в грамматике, приведённой в~\ref{apx:sec:grammar}.
- \index{выражение!порядок вычисления}%
- \index{побочный эффект}%
- \index{порядок!вычислений}%
- Приоритеты и ассоциативность полностью определены, а вот порядок вычисления
- выражения не определён за некоторым исключением даже для подвыражений с побочным
- эффектом. Это значит, что если в определении оператора последовательность
- вычисления его операндов специально не оговаривается, то в реализации можно
- свободно выбирать любой порядок вычислений и даже перемежать правый и левый
- порядок одновременно. Однако любой оператор использует значения своих операндов
- в точном соответствии с грамматическим разбором выражения, в котором он
- встречается.
- %
- % в оригинале в левом нижнем углу страницы надпись ``7. Заказ № 13''
- %
- \begin{ApxComment}
- Это правило отменяет ранее предоставлявшуюся свободу в выборе порядка выполнения
- операций, которые математически коммутативны и ассоциативны, но которые в
- процессе вычислений могут таковыми не оказаться. Это изменение затрагивает
- только вычисления с плавающей точкой, выполняющиеся <<на грани точности>>, и
- ситуаций, когда возможно переполнение.
- \end{ApxComment}
- \index{исключительные ситуации}%
- Контроль за переполнением, делением на нуль и другими исключительными
- ситуациями, возникающими при вычислении выражения, в языке не определён. В
- большинстве существующих реализаций Си при вычислении знаковых целочисленных
- выражений и присваиваний переполнение игнорируется, но результат таких
- вычислений не определён. Трактовки деления на нуль и всех исключительных
- ситуаций, связанных с плавающей точкой, могут не совпадать в разных реализациях;
- иногда для обработки исключительных ситуаций предоставляется нестандартная
- библиотечная функция.
- \subsection{Генерация указателя}
- \label{apx:subsec:generation_of_pointer}
- \index{массив!преобразование имени}%
- \index{преобразование!имени массива}%
- \index{указатель!генерация}%
- Если для некоторого типа $T$ тип выражения или подвыражения есть <<массив из
- $T$>>, то значением этого выражения является указатель на первый элемент
- массива, и тип такого выражения заменяется на тип <<указатель на $T$>>. Такая
- замена типа не делается, если выражение является операндом унарного оператора
- \verb|&|, или операндом операций \verb|++|, \verb|--|, \verb|sizeof|, или левым
- операндом присваивания, или операндом оператора <<\verb|.|>>.
- \index{преобразование!функции}%
- \index{функция!преобразование имени}%
- Аналогично выражение типа <<функция, возвращающая $T$>>, исключая случай, когда
- оно является операндом для \verb|&|, преобразуется в тип <<указатель на функцию,
- возвращающую $T$>>.
- \subsection{Первичные выражения}
- \index{выражение!первичное}%
- \index{первичное выражение}%
- Первичные выражения -- это идентификаторы, константы, стринги и
- \index{выражение!в скобках}%
- выражения в скобках.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{первичное-выражение:}
- \textit{идентификатор}
- \textit{константа}
- \textit{стринг}
- ( \textit{выражение} )
- \end{ShortGramDecsWithCC}
- Идентификатор, если он был должным образом декларирован (о том, как это
- делается, речь пойдёт ниже), -- первичное выражение. Тип идентификатора
- специфицируется в его декларации. Идентификатор есть l-значение, если он
- обозначает объект~(\ref{apx:sec:objects_and_lvalues}) арифметического типа либо
- объект типа <<структура>>, <<объединение>> или <<указатель>>.
- Константа -- первичное выражение. Её тип зависит от формы записи, которая была
- рассмотрена в~\ref{apx:subsec:constants}.
- Стринговый литерал -- первичное выражение.
- \index{стринг!тип}%
- \index{тип!стринга}%
- Изначально его тип -- <<массив из \verb|char|>> (<<массив из \verb|wchar_t|>>
- для стринга литер расширенного набора), но в соответствии с правилом‚
- приведённым в~\ref{apx:subsec:generation_of_pointer}‚ указанный тип обычно
- превращается в <<указатель на \verb|char|>> (<<указатель на \verb|wchar_t|>>) с
- результирующим значением <<указатель на первую литеру стринга>>. Для некоторых
- инициализаторов такая замена типа не
- делается.~(См.~\ref{apx:subsec:initialization}.)
- Выражение в скобках -- первичное выражение, тип и значение которого идентичны
- типу и значению этого же выражения без скобок. Наличие или отсутствие скобок не
- влияет на то, является ли данное выражение l-значением или нет.
- \subsection{Постфиксные выражения}
- \index{операторы!постфиксные \texttt{++} и \texttt{\textminus\textminus}}%
- В постфиксных выражениях операторы выполняются слева направо.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{постфиксное-выражение:}
- \textit{первичное-выражение}
- \textit{постфиксное-выражение} [ \textit{выражение} ]
- \textit{постфиксное-выражение}\
- ( \textit{список-аргументов-выражений\textsubscript{необ}} )
- \textit{постфиксное-выражение} . \textit{идентификатор}
- \textit{постфиксное-выражение} -> \textit{идентификатор}
- \textit{постфиксное-выражение} ++
- \textit{постфиксное-выражение} --
- \textit{список-аргументов-выражений:}
- \textit{выражение-присваивание}
- \textit{список-аргументов-выражений} , \textit{выражение-присваивание}
- \end{ShortGramDecsWithCC}
- \subsubsection{Ссылки на элементы массива}
- \index{массив!ссылки на элементы}%
- \index{массив!индексирование}%
- \index{индексирование массива}%
- Постфиксное выражение, за которым следует выражение в квадратных скобках, есть
- постфиксное выражение, обозначающее ссылку в индексируемый массив. Одно из этих
- двух выражений должно иметь тип <<указатель на $T$>>, где $T$ -- некоторый тип,
- а другое -- принадлежать целочисленному типу; тип результата индексирования есть
- $T$. Выражение \verb|E1[E2]| по определению идентично выражению
- \verb|*((E1)+(E2))|. Подробности
- см.~в~\ref{apx:subsubsec:declarators_of_arrays}.
- \subsubsection{Вызов функции}
- \label{apx:subsubsec:function_call}
- \index{вызов}%
- \index{именователь функции}%
- \index{функция}%
- \index{функция!вызов!семантика}%
- \index{функция!вызов!синтаксис}%
- \index{функция!именователь}%
- Вызов функции есть постфиксное выражение (оно называется именователем функции),
- за которым следуют скобки, содержащие (возможно, пустой) список разделённых
- запятыми выражений-присваиваний~(\ref{apx:subsec:assignment_expression}),
- представляющих собой аргументы этой функции.
- \index{декларация!функции!неявная}%
- \index{функция!неявная декларация}%
- Если постфиксное выражение -- идентификатор, не описанный в текущей области
- действия, то считается, что этот идентификатор как бы описан декларацией
- \begin{ShortCodeParWithCC}{\\\{\}}
- extern int \textit{идентификатор} ( );
- \end{ShortCodeParWithCC}
- \noindent помещённой в самом внутреннем блоке, содержащем вызов соответствующей
- функции.
- \index{по умолчанию!тип функции}%
- \index{указатель!на функцию}%
- \index{функция!тип по умолчанию}%
- \index{функция!указатель на}%
- Постфиксное выражение (после, возможно, неявного описания и генерации указателя,
- см.~\ref{apx:subsec:generation_of_pointer}) должно иметь тип <<указатель на
- функцию, возвращающую $T$>>, где $T$ -- тип возвращаемого значения.
- \begin{ApxComment}
- В первом издании для именователя функции допускался только тип <<функция>>, и,
- чтобы вызвать функцию через указатель, требовался явный оператор \verb|*|.
- ANSI-стандарт поощряет практику некоторых существующих компиляторов,
- разрешающих иметь одинаковый синтаксис для обращения просто к функции и
- обращения к функции, специфицированной указателем. Возможность применения
- старого синтаксиса остаётся.
- \end{ApxComment}
- %
- % в оригинале в левом нижнем углу страницы проставлено ``7*''
- %
- \index{определение!аргумента}%
- \index{определение!параметра}%
- \index{параметр}%
- \index{параметр!определение}%
- \index{прототип функции}%
- \index{функция!аргумент}%
- \index{функция!прототип}%
- Термин \emph{аргумент} используется для выражения, задаваемого в вызове
- функции; термин \emph{параметр} -- для обозначения в определении или описании
- функции получаемого ею объекта (или его идентификатора). Вместо этих понятий
- иногда встречаются термины <<фактический аргумент (параметр)>> и <<формальный
- аргумент (параметр)>>, имеющие те же смысловые различия.
- При вызове функции копируется каждый её аргумент;
- \index{вызов!по значению}%
- передача аргументов осуществляется строго через их значения. Функции разрешается
- изменять значения своих параметров, которые являются лишь копиями
- аргументов-выражений, но эти изменения не могут повлиять на значения самих
- аргументов.
- \index{вызов!по ссылке}%
- Однако можно передать указатель, чтобы дать возможность функции изменить
- значение объекта, на который ссылается этот указатель.
- \index{декларация!функции!новым способом}%
- \index{прототип функции}%
- \index{функция!прототип}%
- \index{функция!в новом стиле}%
- Имеются два способа декларирования функции. В новом способе типы параметров
- задаются явно и являются частью типа функции; такая декларация называется
- прототипом функции.
- \index{декларация!функции!старым способом}%
- \index{функция!в старом стиле}%
- При старом способе типы параметров не указываются. Способы декларирования
- функций обсуждаются
- в~\ref{apx:subsubsec:declarators_of_functions}~и~\ref{apx:subsec:definitions_of_functions}.
- \index{повышение!типа аргумента}%
- \index{преобразование}%
- Если вызов находится в области действия декларации, написанной по-старому,
- каждый его аргумент подвергается операции повышения типа: для целочисленных
- аргументов осуществляется повышение
- целочисленности~(\ref{apx:subsec:integral_promotion}), а для
- \verb|float|-аргументов -- преобразование в \verb|double|. Результат работы
- вызова не определён, если число аргументов не соответствует количеству
- параметров в определении функции или если типы аргументов после повышения не
- согласуются с типами соответствующих параметров. Критерий согласованности типов
- зависит от способа (старого или нового) определения функции. При старом способе
- сравниваются повышенный тип аргумента в вызове и повышенный тип
- соответствующего параметра; при новом способе повышенный тип аргумента и тип
- параметра (без его повышения) должны быть одинаковыми.
- \index{повышение!типа аргумента}%
- \index{преобразование}%
- Если вызов находится в области действия декларации, написанной по-новому,
- аргументы преобразуются, как если бы они присваивались переменным, имеющим типы
- соответствующих параметров прототипа.
- \index{список!аргументов переменной длины}%
- Число аргументов должно совпадать с числом явно описанных параметров, если
- только список параметров не заканчивается многоточием (\verb|, ...|). В
- противном случае число аргументов должно быть больше числа параметров или равно
- ему; <<скрывающиеся>> под многоточием аргументы подвергаются операции повышения
- типа (так, как это было описано в предыдущем абзаце). Если определение функции
- задано по-старому, то типы параметров в прототипе, которые неявно присутствуют в
- вызове, должны соответствовать типам параметров в определении функции после их
- повышения.
- \begin{ApxComment}
- Эти правила особенно усложнились из-за того, что они призваны обслуживать
- смешанный способ (старого с новым) задания функций. По возможности его следует
- избегать.
- \end{ApxComment}
- \index{побочный эффект}%
- Порядок вычисления аргументов не определяется, в разных компиляторах он
- различен. Однако гарантируется, что аргументы и именователь функции вычисляются
- полностью (включая и побочные эффекты) до входа в неё.
- \index{рекурсия}%
- Любая функция допускает рекурсивное обращение.
- \subsubsection{Ссылки на члены структуры}
- \index{оператор!доступа к члену структуры!точка@\texttt{.} (точка)}%
- \index{структура!семантика ссылки на неё}%
- \index{структура!синтаксис ссылки на неё}%
- \index{структура!оператор доступа к её члену!\texttt{.} (точка)}%
- Постфиксное выражение, за которым стоит точка с последующим идентификатором,
- является постфиксным выражением. Выражение первого операнда должно быть
- структурой или объединением, а идентификатор -- именем члена структуры или
- объединения. Значение -- именованный член структуры или объединения, а тип
- значения -- тип члена структуры или объединения. Выражение является l-значением,
- если первое выражение -- l-значение и если тип второго выражения -- не
- <<массив>>.
- \index{оператор!доступа к члену структуры!через указатель \texttt{\textminus\textgreater}}%
- \index{структура!оператор доступа к её члену!через указатель \texttt{\textminus\textgreater}}%
- Постфиксное выражение, за которым указана стрелка (составленная из знаков
- \verb|-| и \verb|>|) с последующим идентификатором, является постфиксным
- выражением. Выражение первого операнда должно быть указателем на структуру
- (объединение), а идентификатор -- именем члена структуры (объединения).
- Результат -- именованный член структуры (объединения), на которую ссылается
- указатель, а тип значения -- тип члена структуры (объединения); результат --
- l-значение, если тип не есть <<массив>>.
- Таким образом, выражение \verb|E1->MOS| означает то же самое, что и выражение
- \verb|(*E1).MOS|. Структуры и объединения рассматриваются
- в~\ref{apx:subsec:declaration_of_structures_and_unions}.
- \begin{ApxComment}
- В первом издании книги уже было приведено правило, по которому имя члена должно
- принадлежать структуре или объединению, упомянутому в постфиксном выражении.
- Там, однако, оговаривалось, что оно не является строго обязательным. Последние
- компиляторы и ANSI делают его обязательным.
- \end{ApxComment}
- \subsubsection{Постфиксные инкрементирование и декрементирование}
- \index{оператор!инкрементации \texttt{++}}%
- \index{оператор!декрементации \texttt{\textminus\textminus}}%
- \index{операторы!постфиксные \texttt{++} и \texttt{\textminus\textminus}}%
- Постфиксное выражение, за которым следует \verb|++| или \verb|--|‚ есть
- постфиксное выражение. Значением такого выражения является значение его
- операнда. После того как значение было взято, операнд увеличивается (\verb|++|)
- или уменьшается (\verb|--|) на $1$. Операнд должен быть l-значением; информация
- об ограничениях, накладываемых на операнд, и деталях операций содержится
- в~\ref{apx:subsec:additive_operators}‚ где обсуждаются аддитивные операторы, и
- в~\ref{apx:subsec:assignment_expression}‚ где рассматривается присваивание.
- Результат инкрементирования или декрементирования не есть l-значение.
- \subsection{Унарные операторы}
- \index{оператор!дополнения побитового до единиц \texttt{\textasciitilde}}%
- \index{оператор!инкрементации \texttt{++}}%
- \index{оператор!декрементации \texttt{\textminus\textminus}}%
- \index{оператор!косвенности \texttt{*}}%
- \index{оператор!унарного минуса \texttt{\textminus}}%
- \index{оператор!унарного плюса \texttt{+}}%
- \index{оператор!sizeof@\texttt{sizeof}}%
- \index{операторы!префиксные \texttt{++} и \texttt{\textminus\textminus}}%
- \index{преобразование|(}%
- Выражения с унарными операторами выполняются справа налево.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{унарное-выражение:}
- \textit{постфиксное-выражение}
- ++ \textit{унарное-выражение}
- -- \textit{унарное-выражение}
- \textit{унарный-оператор} \textit{выражение-приведённое-к-типу}
- sizeof \textit{унарное-выражение}
- sizeof ( \textit{имя-типа} )
- \textit{унарный-оператор:} один из
- & * + - ~ !
- \end{ShortGramDecsWithCC}
- \subsubsection{Префиксные инкрементирование и декрементирование}
- \index{оператор!инкрементации \texttt{++}}%
- \index{оператор!декрементации \texttt{\textminus\textminus}}%
- \index{операторы!постфиксные \texttt{++} и \texttt{\textminus\textminus}}%
- \index{операторы!префиксные \texttt{++} и \texttt{\textminus\textminus}}%
- Унарное выражение, перед которым стоит \verb|++| или \verb|--|, есть унарное
- выражение. Операнд увеличивается (\verb|++|) или уменьшается (\verb|--|) на
- $1$. Значением выражения является значение его операнда после увеличения
- (уменьшения). Операнд всегда -- l-значение; информация об ограничениях на
- операнд и деталях операции содержится в~\ref{apx:subsec:additive_operators}, где
- обсуждаются аддитивные операторы, и в~\ref{apx:subsec:assignment_expression}‚
- где рассматривается присваивание. Результат инкрементирования и
- декрементирования не есть l-значение.
- \subsubsection{Оператор получения адреса}
- \index{переменная!адрес}%
- Унарный оператор \verb|&| обозначает операцию получения адреса своего операнда.
- Операнд должен быть либо l-значением, не ссылающимся ни на поле битов, ни на
- объект, объявленный как \verb|register|, либо иметь тип <<функция>>. Результат
- -- указатель на объект (или функцию), адресуемый этим l-значением. Если тип
- операнда есть $T$, то типом результата является <<указатель на $T$>>.
- \subsubsection{Оператор косвенности}
- \index{оператор!косвенности \texttt{*}}%
- Унарный оператор \verb|*| обозначает операцию косвенности (раскрытия указателя),
- возвращающую объект (или функцию), на который указывает её операнд. Результат
- есть l-значение, если операнд -- указатель на объект арифметического типа или на
- объект типа <<структура>>, <<объединение>> или <<указатель>>. Если тип выражения
- -- <<указатель на $T$>>, то тип результата -- $T$.
- \subsubsection{Оператор унарный плюс}
- \index{оператор!унарного плюса \texttt{+}}%
- Операнд унарного \verb|+| должен иметь арифметический тип, результат -- значение
- операнда. Целочисленный операнд подвергается повышению целочисленности. Типом
- результата является повышенный тип операнда.
- \begin{ApxComment}
- Унарный \verb|+| был добавлен для симметрии с унарным \verb|-|.
- \end{ApxComment}
- \subsubsection{Оператор унарный минус}
- \index{оператор!унарного минуса \texttt{\textminus}}%
- Операнд для унарного \verb|-| должен иметь арифметический тип, результат --
- значение операнда с противоположным знаком. Целочисленный операнд подвергается
- повышению целочисленности. Отрицательное значение от беззнаковой величины
- вычисляется вычитанием приведённого к повышенному типу операнда из максимального
- числа повышенного типа, увеличенного на $1$; однако минус нуль есть нуль. Типом
- результата будет повышенный тип операнда.
- \subsubsection{Оператор обращения разрядов}
- \index{оператор!дополнения побитового до единиц \texttt{\textasciitilde}}%
- \index{операторы!побитовые}%
- Операнд оператора \verb|~| должен иметь целочисленный тип, результат --
- дополнение операнда до единиц по всем разрядам. Выполняется повышение
- целочисленности типа операнда. Если операнд беззнаковый, то результат получается
- вычитанием его значения из самого большого числа повышенного типа. Если операнд
- знаковый, то результат вычисляется посредством приведения <<повышенного
- операнда>> к беззнаковому типу, выполнения операции \verb|~| и обратного
- приведения его к знаковому типу. Тип результата -- повышенный тип операнда.
- \subsubsection{Оператор логического отрицания}
- \index{оператор!логического отрицания \texttt{"!}}%
- Операнд оператора \verb|!| должен иметь арифметический тип или быть указателем.
- Результат равен $1$, если сравнение операнда с $0$ даёт истину, и равен $0$ в
- противном случае. Тип результата -- \verb|int|.
- \subsubsection{Оператор определения размера
- \texorpdfstring{\protect\Verb|sizeof|}{sizeof}}
- \label{apx:subsubsec:sizeof_operator}
- \index{оператор!sizeof@\texttt{sizeof}}%
- \index{структура!размер}%
- Оператор \verb|sizeof| даёт число байтов, требуемое для хранения объекта того
- типа, который имеет его операнд. Операнд -- либо выражение (которое не
- вычисляется), либо имя типа, записанное в скобках. Применённый к \verb|char|
- оператор \verb|sizeof| даёт $1$. Для массива результат равняется общему
- количеству байтов в массиве, для структуры или объединения -- числу байтов в
- объекте, включая и байты-заполнители, которые понадобились бы, если бы из
- элементов составлялся массив. Размер массива из \verb|n| элементов всегда
- равняется \verb|n|, помноженному на размер отдельного его элемента.
- \index{незавершённый тип}%
- \index{тип!незавершённый}%
- Данный оператор нельзя применять к операнду типа <<функция>>, к незавершённому
- типу и к полю битов.
- \index{size{\_}t@\texttt{size{\_}t}}%
- Результат -- беззнаковая целочисленная константа;
- конкретный её тип зависит от реализации. В стандартном головном файле
- \verb|<stddef.h>| (см. приложение~\ref{apx:stdlib}) этот тип определяется под
- именем \verb|size_t|.
- \subsection{Оператор приведения типа}
- \label{apx:subsec:conversion_operator}
- \index{оператор!приведения к типу}%
- \index{преобразование!оператором приведения}%
- \index{приведение к типу}%
- Имя типа, записанное перед унарным выражением в скобках, вызывает приведение
- значения этого выражения к указанному типу.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{выражение-приведённое-к-типу:}
- \textit{унарное-выражение}
- ( \textit{имя-типа} ) \textit{выражение-приведённое-к-типу}
- \end{ShortGramDecsWithCC}
- \noindent Данная конструкция называется \emph{приведением}. Имена типов даны
- в~\ref{apx:subsec:names_of_types}. Результат преобразований описан
- в~\ref{apx:sec:type_conversion}. Выражение с приведением типа не является
- l-значением.
- \subsection{Мультипликативные операторы}
- \label{apx:subsec:multiplication_operators}
- \index{оператор!деления \texttt{\slash}}%
- \index{оператор!деления по модулю \texttt{\%}}%
- \index{оператор!умножения \texttt{*}}%
- \index{операторы!мультипликативные}%
- Мультипликативные операторы \verb|*|, \verb|/| и \verb|%| выполняются слева
- направо.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{мультипликативное-выражение:}
- \textit{выражение-приведённое-к-типу}
- \textit{мультипликативное-выражение} *\
- \textit{выражение-приведённое-к-типу}
- \textit{мультипликативное-выражение} /\
- \textit{выражение-приведённое-к-типу}
- \textit{мультипликативное-выражение} %\
- \textit{выражение-приведённое-к-типу}
- \end{ShortGramDecsWithCC}
- Операнды операторов \verb|*| и \verb|/| должны быть арифметического типа,
- оператора \verb|%| -- целочисленного типа. Над операндами осуществляются
- обычные арифметические преобразования, которые приводят их значения к типу
- результата.
- Бинарный оператор \verb|*| обозначает умножение.
- \index{обрезание!при делении}%
- Бинарный оператор \verb|/| получает частное, а \verb|%| -- остаток от деления
- первого операнда на второй; если второй операнд есть $0$, то результат не
- определён. В противном случае всегда выполняется соотношение:
- \verb|(a/b)*b + a%b| равняется \verb|a|. Если оба операнда не отрицательные, то
- остаток не отрицательный и меньше делителя; в противном случае гарантируется
- только, что абсолютное значение остатка меньше абсолютного значения делителя.
- \subsection{Аддитивные операторы}
- \label{apx:subsec:additive_operators}
- \index{оператор!вычитания \texttt{\textminus}}%
- \index{оператор!сложения \texttt{+}}%
- \index{операторы!аддитивные}%
- Аддитивные операторы \verb|+| и \verb|-| выполняются слева направо. Если
- операнды имеют арифметический тип, то осуществляются обычные арифметические
- преобразования. Для каждого оператора существует ещё несколько дополнительных
- сочетаний типов.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{аддитивное-выражение:}
- \textit{мультипликативное-выражение}
- \textit{аддитивное-выражение} + \textit{мультипликативное-выражение}
- \textit{аддитивное-выражение} - \textit{мультипликативное-выражение}
- \end{ShortGramDecsWithCC}
- Результат выполнения оператора \verb|+| есть сумма его операндов.
- \index{масштабирование целых в арифметике с указателями}%
- \index{неправильная арифметика с указателями}%
- \index{указатели!арифметика с}%
- \index{указатели!коэффициент домножения целых в арифметике с}%
- \index{указатели!неправильная арифметика с}%
- Указатель на объект в массиве можно складывать с целочисленным значением. При
- этом последнее преобразуется в адресное смещение посредством умножения его на
- размер объекта, на который ссылается указатель. Сумма является указателем на
- объект того же типа; только ссылается этот указатель на другой объект того же
- массива, отстоящий от первоначального соответственно вычисленному смещению. Так,
- если \verb|P| -- указатель на объект в массиве, то \verb|P+1| -- указатель на
- его следующий объект. Если полученный в результате суммирования указатель
- выводит за границы массива, то за исключением случая, когда он ссылается на
- место, находящееся непосредственно за концом массива, результат будет
- неопределённым.
- \begin{ApxComment}
- Возможность для указателя ссылаться на точку, расположенную сразу за концом
- массива, является новой. Она узаконивает общепринятую практику организации
- циклического перебора элементов массива.
- \end{ApxComment}
- Результат выполнения оператора \verb|-| есть разность операндов. Из указателя
- можно вычитать значение любого целочисленного типа с теми же преобразованиями и
- при тех же условиях, что и в сложении.
- Если к двум указателям на объекты одного и того же типа применить оператор
- вычитания, то в результате получится целочисленное значение со знаком,
- представляющее собой расстояние между объектами, на которые ссылаются эти
- указатели; указатель на следующий объект на $1$ больше указателя на предыдущий
- объект.
- \index{ptrdiff{\_}t@\texttt{ptrdiff{\_}t}}%
- Тип результата зависит от реализации; в стандартном головном файле
- \verb|<stddef.h>| он определён под именем \verb|ptrdiff_t|. Значение не
- определено, если указатели ссылаются на объекты не одного и того же массива;
- однако если \verb|P| указывает на последний элемент массива, то \verb|(P+1)-P|
- имеет значение, равное $1$.
- \subsection{Операторы сдвига}
- \label{apx:subsec:shift_operators}
- \index{оператор!левого сдвига \texttt{\textless}\texttt{\textless}}%
- \index{оператор!правого сдвига \texttt{\textgreater}\texttt{\textgreater}}%
- \index{операторы!побитовые}%
- \index{операторы!сдвига}%
- Операторы сдвига \verb|<<| и \verb|>>| выполняются слева направо. Для обоих
- операторов каждый операнд должен иметь целочисленный тип, и каждый из них
- подвергается повышению целочисленности. Тип результата совпадает с повышенным
- типом левого операнда. Результат не определён, если правый операнд отрицателен
- или его значение превышает число битов в типе левого выражения или равно ему.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{сдвиговое-выражение:}
- \textit{аддитивное-выражение}
- \textit{сдвиговое-выражение} >> \textit{аддитивное-выражение}
- \textit{сдвиговое-выражение} << \textit{аддитивное-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Значение \verb|E1 << E2| равно значению \verb|E1| (рассматриваемому
- как цепочка битов), сдвинутому влево на \verb|E2| бит; при отсутствии
- переполнения такая операция эквивалентна умножению на $2^{\mathrm{E}2}$.
- Значение \verb|E1 >> E2| равно значению \verb|E1|, сдвинутому вправо на
- \verb|E2| битовые позиции. Если \verb|E1| беззнаковое или имеет неотрицательное
- значение, то правый сдвиг эквивалентен делению на $2^{\mathrm{E}2}$‚ в противном
- случае результат зависит от реализации.
- \subsection{Операторы отношения}
- \index{оператор!меньше или равно \texttt{\textless=}}%
- \index{оператор!меньше \texttt{\textless}}%
- \index{оператор!больше или равно \texttt{\textgreater=}}%
- \index{оператор!больше \texttt{\textgreater}}%
- \index{операторы!отношения}%
- Операторы отношения выполняются слева направо, однако это свойство едва ли может
- оказаться полезным; согласно грамматике языка выражение \verb|a<b<c| трактуется
- так же, как \verb|(a<b)<c|‚ а результат вычисления \verb|a<b| всегда есть $0$
- или $1$.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{выражение-отношения:}
- \textit{сдвиговое-выражение}
- \textit{выражение-отношения} < \textit{сдвиговое-выражение}
- \textit{выражение-отношения} > \textit{сдвиговое-выражение}
- \textit{выражение-отношения} <= \textit{сдвиговое-выражение}
- \textit{выражение-отношения} >= \textit{сдвиговое-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Операторы: \verb|<| (меньше), \verb|>| (больше), \verb|<=| (меньше или
- равно) и \verb|>=| (больше или равно) -- все выдают $0$, если специфицируемое
- отношение ложно, и $1$, если оно истинно. Тип результата -- \verb|int|. Над
- арифметическими операндами выполняются обычные арифметические преобразования.
- \index{сравнение указателей}%
- \index{указатели!сравнение}%
- Можно сравнивать указатели на объекты одного и того же (без учёта
- квалификаторов) типа; результат будет зависеть от их относительного расположения
- в памяти. Допускается, однако, сравнение указателей на разные части одного и
- того же объекта: если два указателя ссылаются на один и тот же простой объект,
- то они равны; если они ссылаются на члены одной структуры, то указатель на член
- с более поздней декларацией в структуре больше; если указатели ссылаются на
- члены одного итого же объединения, то они равны; если указатели ссылаются на
- элементы некоторого массива, то сравнение этих указателей эквивалентно сравнению
- их индексов. Если \verb|P| указывает на последний элемент массива, то \verb|P+1|
- больше, чем \verb|P|, хотя \verb|P+1| <<выводит>> нас за границы массива. В
- остальных случаях результат сравнения не определён.
- \begin{ApxComment}
- Эти правила несколько ослабили ограничения, установленные в первой редакции
- языка. Они позволяют сравнивать указатели на различные члены структуры и
- объединения и легализуют сравнение с указателем, ссылающимся на место, которое
- расположено непосредственно за концом массива.
- \end{ApxComment}
- \subsection{Операторы равенства}
- \index{оператор!неравенства \texttt{"!=}}%
- \index{оператор!равенства \texttt{==}}%
- \index{операторы!равенства}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{выражение-равенства:}
- \textit{выражение-отношения}
- \textit{выражение-равенства} == \textit{выражение-отношения}
- \textit{выражение-равенства} != \textit{выражение-отношения}
- \end{ShortGramDecsWithCC}
- \noindent Операторы \verb|==| (равно) и \verb|!=| (не равно) являются аналогами
- операторов отношения с той лишь разницей, что они имеют более низкий приоритет.
- (Таким образом, \verb|a<b == c<d| есть $1$ тогда и только тогда, когда отношения
- \verb|a<b| и \verb|c<d| оба одновременно истинны или ложны.)
- \index{сравнение указателей}%
- \index{указатели!сравнение}%
- Операторы равенства подчиняются тем же правилам, что и операторы отношения. И
- кроме того, они дают возможность сравнивать указатель с целочисленным
- константным выражением, значение которого равно нулю, и с указателем на
- \verb|void|.~(См.~\ref{apx:subsec:pointers_and_integers}.)
- \index{операторы!побитовые|(}%
- \subsection{Оператор побитового И}
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{И-выражение:}
- \textit{выражение-равенства}
- \textit{И-выражение} & \textit{выражение-равенства}
- \end{ShortGramDecsWithCC}
- \noindent Выполняются обычные арифметические преобразования; результат --
- побитовое И операндов. Оператор применяется только к целочисленным операндам.
- \subsection{Оператор побитового исключающего ИЛИ}
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{исключающее-ИЛИ-выражение:}
- \textit{И-выражение}
- \textit{исключающее-ИЛИ-выражение} ^ \textit{И-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Выполняются обычные арифметические преобразования; результат --
- побитовое исключающее ИЛИ операндов. Оператор применяется только к целочисленным
- операндам.
- \subsection{Оператор побитового ИЛИ}
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{ИЛИ-выражение:}
- \textit{исключающее-ИЛИ-выражение}
- \textit{ИЛИ-выражение} | \textit{исключающее-ИЛИ-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Выполняются обычные арифметические преобразования; результат --
- побитовое ИЛИ операндов. Оператор применяется только к целочисленным операндам.
- \index{операторы!побитовые|)}%
- \subsection{Оператор логического И}
- \index{оператор!логического И \texttt{\&\&}}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{логическое-И-выражение:}
- \textit{ИЛИ-выражение}
- \textit{логическое-И-выражение} && \textit{ИЛИ-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Операторы \verb|&&| выполняются слева направо. Оператор \verb|&&|
- выдаёт $1$, если оба операнда не равны нулю, и $0$ в противном случае. В отличие
- от \verb|&|, \verb|&&| гарантирует, что вычисления будут проводиться слева
- направо: вычисляется первый операнд со всеми побочными эффектами; если он равен
- $0$, то значение выражения есть $0$. В противном случае вычисляется правый
- операнд, и, если он равен $0$, то значение выражения есть $0$, в противном
- случае оно равно $1$.
- Операнды могут принадлежать разным типам, но либо операнд должен иметь
- арифметический тип, либо быть указателем. Тип результата -- \verb|int|.
- \subsection{Оператор логического ИЛИ}
- \index{оператор!логического ИЛИ \texttt{"|"|}}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{логическое-ИЛИ-выражение:}
- \textit{логическое-И-выражение}
- \textit{логическое-ИЛИ-выражение} || \textit{логическое-И-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Операторы \verb+||+ выполняются слева направо. Оператор \verb+||+
- выдаёт $1$, если по крайней мере один из операндов не равен нулю, и $0$ в
- противном случае. В отличие от \verb+|+, оператор \verb+||+ гарантирует, что
- вычисления будут проводиться слева направо: вычисляется первый операнд, включая
- все побочные эффекты; если он не равен $0$, то значение выражения есть $1$. В
- противном случае вычисляется правый операнд, и, если он не равен $0$, то
- значение выражения есть $1$, в противном случае оно равно $0$.
- Операнды могут принадлежать разным типам, но либо операнд должен иметь
- арифметический тип, либо быть указателем. Тип результата -- \verb|int|.
- \subsection{Условный оператор}
- \index{условное выражение}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{условное-выражение:}
- \textit{логическое-ИЛИ-выражение}
- \textit{логическое-ИЛИ-выражение} ?\
- \textit{выражение} : \textit{условное-выражение}
- \end{ShortGramDecsWithCC}
- \noindent Вычисляется первое выражение, включая все побочные эффекты; если оно
- не равно $0$, то результат есть значение второго выражения, в противном случае
- -- значение третьего выражения. Вычисляется только один из двух последних
- операндов: второй или третий. Если второй и третий операнды арифметические, то
- выполняются обычные арифметические преобразования, приводящие к некоторому
- общему типу, который и будет типом результата. Если оба операнда имеют тип
- \verb|void|, или являются структурами или объединениями одного и того же типа,
- или представляют собой указатели на объекты одного и того же типа, то результат
- будет иметь тот же тип, что и операнды. Если один из операндов имеет тип
- <<указатель>>, а другой является константой $0$, то $0$ приводится к типу
- <<указатель>>, этот же тип будет иметь и результат. Если один операнд является
- указателем на \verb|void|, а второй -- указатель другого типа, то последний
- преобразуется в указатель на \verb|void|, который и будет типом результата.
- %
- % исправлена опечатка
- % в оригинале "операды"
- %
- \index{квалификатор типа}%
- \index{тип!квалификатор}%
- При сравнении типов указателей квалификаторы
- типов~(\ref{apx:subsec:type_specifiers}) объектов, на которые указатели
- ссылаются, во внимание не принимаются, но тип результата наследует квалификаторы
- обеих ветвей условного выражения.
- \subsection{Выражения присваивания}
- \label{apx:subsec:assignment_expression}
- \index{выражение!присваивание}%
- \index{операторы!присваивания}%
- \index{оператор!присваивания \texttt{=}}%
- \index{оператор!присваивания \texttt{*=}}%
- \index{оператор!присваивания \texttt{\slash=}}%
- \index{оператор!присваивания \texttt{\%=}}%
- \index{оператор!присваивания \texttt{+=}}%
- \index{оператор!присваивания \texttt{\textminus=}}%
- \index{оператор!присваивания \texttt{\textless}\texttt{\textless=}}%
- \index{оператор!присваивания \texttt{\textgreater}\texttt{\textgreater=}}%
- \index{оператор!присваивания \texttt{\&=}}%
- \index{оператор!присваивания \texttt{\textasciicircum=}}%
- \index{оператор!присваивания \texttt{"|=}}%
- \index{преобразование!присваиванием}%
- \index{присваивание!выражение}%
- Существует несколько операторов присваивания; они выполняются справа налево.
- {\setlength{\codeIndent}{\codeIndentBk-0.25em}
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{выражение-присваивания:}
- \textit{условное-выражение}
- \textit{унарное-выражение} \textit{оператор-присваивания}\
- \textit{выражение-присваивания}
- \textit{оператор-присваивания:} один из
- = *= /= %= += -= <<= >>= &= ^= |=
- \end{ShortGramDecsWithCC}
- \setlength{\codeIndent}{\codeIndentBk}}
- \noindent Операторы присваивания в качестве левого операнда требуют l-значения,
- причём модифицируемого; это значит, что оно не может быть массивом, или иметь
- незавершённый тип, или быть функцией. Тип левого операнда, кроме того, не может
- иметь
- \index{квалификатор типа}%
- квалификатор \verb|const|; и, если он является структурой или объединением, в
- них не должно быть членов или подчленов (для вложенных структур или объединений)
- с квалификаторами \verb|const|. Тип выражения присваивания -- тип его левого
- операнда, а значение -- значение его левого операнда после завершения
- присваивания.
- \index{преобразование!присваиванием}%
- В простом присваивании с оператором \verb|=| значение выражения замещает объект,
- на который ссылается l-значение. При этом должно выполняться одно из следующих
- условий: оба операнда имеют арифметический тип (если типы операндов разные,
- правый операнд приводится к типу левого операнда); оба операнда есть структуры
- или объединения одного и того же типа; один операнд есть указатель, а другой --
- указатель на \verb|void|; левый операнд -- указатель, а правый -- константное
- выражение со значением $0$; оба операнда -- указатели на функции или объекты,
- имеющие одинаковый тип (за исключением возможного отсутствия \verb|const| или
- \verb|volatile| у правого операнда).
- Выражение \verb|E1 |\textit{\Verb|op|}\verb| = E2| эквивалентно выражению
- \verb|E1 = E1 |\textit{\Verb|op|}\verb| (E2)| с одним исключением: \verb|E1|
- вычисляется только один раз.
- \subsection{Оператор запятая}
- \label{apx:subsec:operator_comma}
- \index{оператор!запятая \texttt{,}}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{выражение:}
- \textit{выражение-присваивания}
- \textit{выражение} , \textit{выражение-присваивания}
- \end{ShortGramDecsWithCC}
- \noindent Два выражения, разделённые запятой, вычисляются слева направо, и
- значение левого выражения отбрасывается. Тип и значение результата совпадают с
- типом и значением правого операнда. Вычисление всех побочных эффектов левого
- операнда завершается перед началом вычисления правого операнда. В контексте, в
- котором запятая имеет специальное значение, например в списках аргументов
- функций~(\ref{apx:subsubsec:function_call}) или в списках
- инициализаторов~(\ref{apx:subsec:initialization}) (здесь в качестве
- синтаксических единиц фигурируют выражения присваивания), оператор запятая может
- появиться только в группирующих скобках. Например, в
- \begin{ShortCodePar}
- f(a, (t=3, t+2), c)
- \end{ShortCodePar}
- \noindent три аргумента, из которых второй имеет значение $5$.
- \subsection{Константные выражения}
- \label{apx:subsec:constant_expressions}
- \index{выражение!константное}%
- \index{константное выражение}%
- Синтаксически, константное выражение -- это выражение с ограниченным
- подмножеством операторов:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{константное-выражение:}
- \textit{условное-выражение}
- \end{ShortGramDecsWithCC}
- \noindent При указании \verb|case|-меток в переключателе, задании границ
- массивов и длин полей битов, на месте значений перечислимых констант и
- инициализаторов, а также в некоторых выражениях для препроцессора требуются
- выражения, вычисление которых приводит к константе.
- Константные выражения не могут содержать присваиваний, операторов
- инкрементирования и декрементирования, вызовов функций и операторов-запятых;
- перечисленные ограничения не распространяются на операнд \verb|sizeof|. Если
- требуется получить целочисленное константное выражение, то его операнды должны
- состоять из целых, перечислимых, литерных и плавающих констант; операции
- приведения должны специфицировать целочисленный тип, а любая плавающая константа
- -- приводиться к целому. Из этого следует, что в константном выражении не может
- быть массивов, операций раскрытия указателя, получения адреса и доступа к полям
- структуры. (Однако для \verb|sizeof| возможны операнды любого вида.)
- Для константных выражений в инициализаторах допускается б\'{o}льшая свобода;
- операндами могут быть константы любого типа, а к внешним или статическим
- объектам и внешним и статическим массивам, индексируемым константными
- выражениями, возможно применять унарный оператор \verb|&|. Унарный оператор
- \verb|&| может также неявно <<присутствовать>> при использовании массива без
- индекса или функции без списка аргументов. Вычисление инициализатора должно
- давать константу или адрес ранее декларированного внешнего или статического
- объекта плюс-минус константа.
- Меньшая свобода допускается для целочисленных константных выражений,
- используемых после \verb|#if|: не разрешаются \verb|sizeof|-выражения‚
- перечислимые константы и операции приведения
- типа.~(См.~\ref{apx:subsec:conditional_compilation}.)
- \index{преобразование|)}%
- \index{выражение|)}%
- \section{Декларации}
- \index{декларация|(}%
- То, каким образом интерпретируется каждый идентификатор, специфицируется
- декларациями; они не всегда резервируют память для описываемых ими
- идентификаторов.
- \index{декларация!а не определение}%
- \index{память!резервирование}%
- \index{резервирование памяти}%
- Декларации, резервирующие память, называются \emph{определениями} и имеют
- следующий вид:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{декларация:}
- \textit{спецификаторы-декларации}\
- \textit{список-иниц-деклараторов\textsubscript{необ}};
- \end{ShortGramDecsWithCC}
- \noindent Деклараторы в \textit{список-иниц-деклараторов} содержат декларируемые
- идентификаторы; \textit{спецификаторы-декларации} представляют собой
- последовательности, состоящие из спецификаторов типа и класса памяти.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{спецификаторы-декларации:}
- \textit{спецификатор-класса-памяти}\
- \textit{спецификаторы-декларации\textsubscript{необ}}
- \textit{спецификатор-типа}\
- \textit{спецификаторы-декларации\textsubscript{необ}}
- \textit{квалификатор-типа}\
- \textit{спецификаторы-декларации\textsubscript{необ}}
- \textit{список-иниц-деклараторов:}
- \textit{иниц-декларатор}
- \textit{список-иниц-деклараторов} , \textit{иниц-декларатор}
- \textit{иниц-декларатор:}
- \textit{декларатор}
- \textit{декларатор} = \textit{инициализатор}
- \end{ShortGramDecsWithCC}
- \noindent Деклараторы содержат подлежащие описанию имена. Мы рассмотрим их
- позже, в~\ref{apx:subsec:declarators}. Либо декларация должна иметь по крайней
- мере один декларатор, либо её спецификатор типа должен определять тег структуры
- или объединения, либо -- задавать члены перечисления; пустая декларация
- незаконна.
- \subsection{Спецификаторы класса памяти}
- \index{декларация!класса памяти}%
- \index{декларация!typedef@\texttt{typedef}}%
- \index{определение!класса памяти}%
- \index{память!декларация класса}%
- \index{память!определение}%
- \index{память!спецификатор класса}%
- \index{спецификатор!класса памяти}%
- \index{спецификатор!auto@\texttt{auto}}%
- \index{спецификатор!extern@\texttt{extern}}%
- \index{спецификатор!register@\texttt{register}}%
- \index{спецификатор!static@\texttt{static}}%
- \index{auto@\texttt{auto}}%
- \index{extern@\texttt{extern}}%
- \index{register@\texttt{register}}%
- \index{static@\texttt{static}!спецификатор класса памяти}%
- \index{typedef-декларация@\texttt{typedef}-декларация}%
- Класс памяти специфицируется следующим образом:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{спецификатор-класса-памяти:}
- auto
- register
- static
- extern
- typedef
- \end{ShortGramDecsWithCC}
- \noindent Смысл классов памяти обсуждался
- в~\ref{apx:sec:what_identificators_mean}.
- Спецификаторы \verb|auto| и \verb|register| дают декларируемым объектам класс
- автоматической памяти, и эти спецификаторы можно применять только внутри
- функций. Декларации с \verb|auto| и \verb|register| одновременно являются
- определениями и резервируют память. Спецификатор \verb|register| эквивалентен
- \verb|auto|, но содержит подсказку, сообщающую, что в программе декларируемые им
- объекты используются интенсивно. На регистрах может быть размещено лишь
- небольшое число объектов, причём определённого типа; указанные ограничения
- зависят от реализации.
- \index{регистр, адрес}%
- В любом случае к \verb|register|-объекту нельзя применять
- (явно или неявно) унарный оператор \verb|&|.
- \begin{ApxComment}
- Новым является правило, согласно которому вычислять адрес объекта класса
- \verb|register| нельзя, а класса \verb|auto| можно.
- \end{ApxComment}
- \index{static-переменные@\texttt{static}-переменные!внутренние}%
- Спецификатор \verb|static| даёт декларируемым объектам класс статической памяти,
- он может использоваться и внутри, и вне функций. Внутри функции этот
- спецификатор вызывает выделение памяти и служит определением; его роль вне
- функций будет объяснена в~\ref{apx:subsec:links}.
- Декларация со спецификатором \verb|extern|, используемая внутри функции,
- объявляет, что для декларируемого объекта где-то выделена память; о её роли вне
- функций будет сказано в~\ref{apx:subsec:links}.
- %
- % исправлена опечатка
- % в оригинале было "external"
- %
- Спецификатор \verb|typedef| не резервирует никакой памяти и назван
- спецификатором класса памяти из соображений стандартности синтаксиса; речь об
- этом спецификаторе пойдёт в~\ref{apx:subsec:typedef_declaration}.
- Декларация может содержать не более одного спецификатора класса памяти.
- \index{опущенный спецификатор!класса памяти}%
- \index{память!спецификатор класса!опущенный}%
- \index{спецификатор!класса памяти!опущенный}%
- Если он в декларации отсутствует, то действуют следующие правила: считается, что
- объекты, декларируемые внутри функций, имеют класс \verb|auto|; функции,
- декларируемые внутри функций, -- класс \verb|extern|;
- \index{связь!внешняя}%
- объекты и функции, декларируемые вне функций, -- статические и имеют внешние
- связи~(\ref{apx:sec:external_declarations},~\ref{apx:sec:scope}).
- \subsection{Спецификаторы типа}
- \label{apx:subsec:type_specifiers}
- \index{спецификатор!типа}%
- \index{тип!спецификатор}%
- \index{char@\texttt{char}!тип}%
- \index{double@\texttt{double}!тип}%
- \index{float@\texttt{float}!тип}%
- \index{int@\texttt{int}!тип}%
- \index{long@\texttt{long}!тип}%
- \index{short@\texttt{short}}%
- \index{signed@\texttt{signed}!тип}%
- \index{unsigned@\texttt{unsigned}!тип}%
- \index{void@\texttt{void}!тип}%
- Спецификаторы типа определяются следующим образом:
- \begin{LongGramDecsWithCC}{\\\{\}}
- \textit{спецификатор-типа:}
- void
- char
- short
- int
- long
- float
- double
- signed
- unsigned
- \textit{структ-или-объед-спецификатор}
- \textit{enum-спецификатор}
- \textit{typedef-имя}
- \end{LongGramDecsWithCC}
- \noindent Вместе с \verb|int| допускается использование ещё какого-то одного
- слова -- \verb|long| или \verb|short|; причём сочетание \verb|long int| имеет
- тот же смысл, что и просто \verb|long|; аналогично \verb|short int| -- то же
- самое, что и \verb|short|. Слово \verb|long| может употребляться вместе с
- \verb|double|. С \verb|int| и другими его модификациями (\verb|short|,
- \verb|long| или \verb|char|) разрешается употреблять одно из слов \verb|signed|
- или \verb|unsigned|.
- \index{опущенный спецификатор!типа}%
- \index{тип!опущенный спецификатор}%
- Любое из последних может использоваться самостоятельно, в этом случае
- подразумевается \verb|int|. Спецификатор \verb|signed| бывает полезен, когда
- требуется обеспечить, чтобы \verb|char|-объекты имели знак; его можно применять
- и к другим целочисленным типам, но в этих случаях он избыточен.
- За исключением описанных выше случаев декларация не может содержать более одного
- спецификатора типа. Если в декларации нет ни одного спецификатора типа, то
- имеется в виду тип \verb|int|.
- \index{квалификатор типа}%
- \index{тип!квалификатор}%
- \index{const@\texttt{const}}%
- \index{volatile@\texttt{volatile}}%
- Для указания особых свойств декларируемых объектов предназначаются
- квалификаторы:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{квалификатор-типа:}
- const
- volatile
- \end{ShortGramDecsWithCC}
- \noindent Квалификаторы типа могут употребляться с любым спецификатором типа.
- \verb|const|-объект разрешается инициализировать, однако присваивать ему
- что-либо в дальнейшем запрещается. Смысл квалификатора \verb|volatile| зависит
- от реализации.
- \begin{ApxComment}
- Средства \verb|const| и \verb|volatile| (изменчивый) введены ANSI-стандартом.
- Квалификатор \verb|const| применяется, чтобы разместить объекты в памяти,
- открытой только на чтение, или чтобы способствовать возможной оптимизации.
- Назначение квалификатора \verb|volatile| -- подавить оптимизацию, которая без
- этого указания могла бы возникнуть. Например, в машинах, где адреса регистров
- ввода-вывода отображены на адресное пространство памяти, указатель на регистр
- некоторого устройства мог бы быть декларирован как \verb|volatile|‚ чтобы
- запретить компилятору экономить очевидно избыточную ссылку через указатель.
- Компилятор может игнорировать указанные квалификаторы, однако обязан
- сигнализировать о явных попытках изменить значение \verb|const|-объектов.
- \end{ApxComment}
- \subsection{Декларации структур и объединений}
- \label{apx:subsec:declaration_of_structures_and_unions}
- \index{объединение, тег|(}%
- \index{спецификатор!struct@\texttt{struct}}%
- \index{спецификатор!union@\texttt{union}}%
- \index{структура!вложенная}%
- \index{структура!тег|(}%
- \index{тег!объединения|(}%
- \index{тег!структуры|(}%
- \index{union@\texttt{union}!спецификатор}%
- Структура -- это объект, состоящий из последовательности именованных членов
- различных типов. Объединение -- объект, который в каждый момент времени содержит
- один из нескольких членов различных типов.
- \index{декларация!структуры}%
- \index{структура!декларация}%
- \index{декларация!union@\texttt{union}}%
- \index{struct, спецификатор@\texttt{struct}, спецификатор}%
- \index{union@\texttt{union}!декларация}%
- Декларации структур и объединений имеют один и тот же вид.
- {\setlength{\codeIndent}{\codeIndentBk-0.75em}%
- \begin{ShortGramDecsWithCC}{\\\[\]}
- \textit[структ-или-объед-спецификатор:]
- \textit[структ-или-объед] \textit[идентификатор\textsubscript[необ]]\
- { \textit[список-структ-деклараций] }
- \textit[структ-или-объед] \textit[идентификатор]
- \textit[структ-или-объед:]
- struct
- union
- \end{ShortGramDecsWithCC}
- \setlength{\codeIndent}{\codeIndentBk}}
- \noindent \emph{Список-структ-деклараций} является последовательностью деклараций членов структуры или объединения:
- {\setlength{\codeIndent}{\codeIndentBk-0.75em}%
- \begin{LongGramDecsWithCC}{\\\{\}}
- \textit{список-структ-деклараций:}
- \textit{структ-декларация}
- \textit{список-структ-деклараций}\
- \textit{структ-декларация}
- \textit{структ-декларация:}
- \textit{список-спецификаторов-квалификаторов}\
- \textit{список-структ-деклараторов};
- \textit{список-спецификаторов-квалификаторов:}
- \textit{спецификатор-типа}\
- \textit{список-спецификаторов-квалификаторов\textsubscript{необ}}
- \textit{квалификатор-типа}\
- \textit{список-спецификаторов-квалификаторов\textsubscript{необ}}
- \textit{список-структ-деклараторов:}
- \textit{структ-декларатор}
- \textit{список-структ-деклараторов} , \textit{структ-декларатор}
- \end{LongGramDecsWithCC}
- \setlength{\codeIndent}{\codeIndentBk}}
- \noindent Обычно \textit{структ-декларатор} -- это просто декларатор члена
- структуры или объединения. Членом структуры может быть также некоторая
- последовательность битов заданной длины. Такой член называется
- \index{битовое поле}%
- \index{битовое поле!декларация}%
- \index{декларация!поля битов}%
- \emph{полем-бит} или просто \emph{полем}; указатель его длины отделяется от
- декларатора имени поля двоеточием.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{структ-декларатор:}
- \textit{декларатор}
- \textit{декларатор\textsubscript{необ}} : \textit{константное-выражение}
- \end{ShortGramDecsWithCC}
- Спецификатор типа, имеющий вид
- \begin{ShortGramDecsWithCC}{\\\[\]}
- \textit[структ-или-объед] \textit[идентификатор]\
- { \textit[список-структ-деклараций] }
- \end{ShortGramDecsWithCC}
- \noindent декларирует \textit{идентификатор} как \emph{тег} структуры
- (объединения), задаваемый списком. Последующие декларации в той же или более
- внутренней области действия могут ссылаться в спецификаторе на этот тип при
- помощи тега (без списка):
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{структ-или-объед} \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \noindent%
- \index{незавершённый тип}%
- \index{тип!незавершённый}%
- Если спецификатор с тегом без списка обнаружен в тот момент, когда тег
- ещё не декларирован, то считается, что специфицирован \emph{незавершённый тип}.
- На объект с незавершённым типом структуры (объединения) можно ссылаться в
- контексте, где не нужен его размер, например, в декларациях (но не в
- определениях), в спецификации указателя или при задании \verb|typedef|, но ни в
- каких других случаях. Тип становится завершённым при появлении спецификатора с
- тегом структуры или объединения, содержащего список деклараций. Но и в
- спецификаторах со списком определяемые ими типы внутри списка остаются
- незавершёнными до тех пор, пока не встретится завершающая спецификатор фигурная
- скобка.
- В структуру не могут входить члены с незавершённым типом. Следовательно‚ нельзя
- декларировать структуру (объединение), содержащую саму себя.
- \index{структура!ссылающаяся на себя}%
- \index{структуры взаимно рекурсивные}%
- Однако, помимо того что теги являются именами типов структур или объединений,
- они позволяют определять структуры (объединения), ссылающиеся сами на себя;
- структура (объединение) может содержать указатель на объект этой же структуры
- (объединения), поскольку указатели с незавершёнными типами декларировать
- разрешено.
- В отношении деклараций вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{структ-или-объед} \textit{идентификатор} ;
- \end{ShortGramDecsWithCC}
- \noindent которые объявляют структуру или объединение, однако не имеют ни
- списка, ни деклараторов, действует специальное правило. Даже если этот
- идентификатор уже был декларирован во внешней области
- действия~(\ref{apx:subsec:lexical_scope}) в качестве тега структуры или
- объединения, в текущей области действия указанная декларация делает его тегом
- нового незавершённого типа для структуры или объединения.
- \begin{ApxComment}
- Это <<неясное>> правило введено ANSI-стандартом. Оно позволяет во внутренней
- области действия программы создавать <<взаимно-рекурсивные>> декларации структур
- с тегами, которые уже могли быть объявлены во внешней области действия.
- \end{ApxComment}
- Спецификатор структуры или объединения со списком, но без тега, представляет
- собой уникальный тип; на него можно сослаться только в той декларации, частью
- которой он является.
- \index{структура!имя члена}%
- \index{член структуры, имя}%
- Имена членов и тегов не <<конфликтуют>> ни между собой, ни с именами обычных
- переменных. Имя члена нельзя употребить дважды в одной и той же структуре или
- объединении, но одно и то же имя можно использовать в различных структурах и
- объединениях.
- \begin{ApxComment}
- В первом издании этой книги имена членов не были локализованы в своей структуре
- или объединении. Однако такая локализация стала общеупотребительной ещё до
- принятия ANSI-стандарта для Си.
- \end{ApxComment}
- \index{тег!структуры|)}%
- \index{тег!объединения|)}%
- \index{структура!тег|)}%
- \index{объединение, тег|)}%
- Член (не поле) может быть объектом любого типа.
- \index{битовое поле!выравнивание}%
- Поле (которое может и не иметь декларатора и, следовательно, быть без имени)
- имеет тип \verb|int|, \verb|unsigned int| или \verb|signed int| и
- интерпретируется как объект целочисленного типа с заданным числом битов;
- рассматривается ли поле типа \verb|int| как знаковое, зависит от реализации.
- Также от реализации зависит способ и порядок <<упаковки>> соседних полей в
- памяти. Если поле, следующее за другим полем, не помещается в частично
- заполненной ячейке памяти, то либо оно будет разрезано на части, которые попадут
- в разные ячейки, либо в структуре возникнут пропуски из неиспользуемых разрядов.
- Поле без имени длины $0$ предписывает пропустить оставшиеся разряды и следующее
- поле расположить с начала ячейки памяти.
- \begin{ApxComment}
- В сравнении с первым изданием ANSI-стандарт устанавливает ещё большую
- зависимость полей от реализации. Разумно правила языка, касающиеся размещения
- полей битов, рассматривать без каких-либо оговорок как
- <<реализационно-зависимые>>. Структуры с полями битов полезны и как
- универсальный способ минимизации памяти, требуемой под структуры, возможно, за
- счёт увеличения количества команд и замедления доступа к полям, и как способ
- описания побитового расположения информации. Во втором случае необходимо знать
- особенности конкретной реализации.
- \end{ApxComment}
- Члены структуры имеют адреса, возрастающие в порядке написания их деклараций.
- Член структуры (не поле) выравнивается по адресуемым границам слов в
- соответствии со своим типом; следовательно, в структуре могут возникать
- безымянные <<дыры>>. Если указатель на структуру привести к типу указателя на её
- первый член, то в результате получится указатель на первый член структуры.
- Объединение можно считать как бы структурой, все члены которой имеют смещение
- $0$ от её начала, и которая обладает достаточным размером, чтобы вмещать любой
- из своих членов. В каждый отдельный момент объединение может хранить значение
- только одного своего члена. Если указатель на объединение привести к типу
- какого-то из его членов, то в результате получится указатель на этот член.
- Вот простой пример декларации структуры, которая содержит массив из 20 литер,
- целое и две ссылки на такие же структуры.
- \begin{ShortCodePar}
- struct tnode {
- char tword[20];
- int count;
- struct tnode *left;
- struct tnode *right;
- };
- \end{ShortCodePar}
- \noindent Если после указанной декларации поместить запись
- \begin{ShortCodePar}
- struct tnode s, *sp;
- \end{ShortCodePar}
- \noindent то она будет определять \verb|s| как структуру заданного вида, а
- \verb|sp| -- как указатель на такую структуру. Согласно приведённым определениям
- выражение
- \begin{ShortCodePar}
- sp->count
- \end{ShortCodePar}
- \noindent есть ссылка на член \verb|count| в структуре, на которую указывает
- \verb|sp|;
- \begin{ShortCodePar}
- s.left
- \end{ShortCodePar}
- \noindent -- указатель на левое поддерево в структуре \verb|s|; а
- \begin{ShortCodePar}
- s.right->tword[0]
- \end{ShortCodePar}
- \noindent есть первая литера из \verb|tword| -- члена правого поддерева
- \verb|s|.
- Вообще говоря, нет способа проконтролировать, используется тот ли член
- объединения, которому последний раз присваивалось значение. Однако гарантируется
- выполнение правила, облегчающего работу с членами объединения: если объединение
- содержит несколько структур, начинающихся с общей для них последовательности
- данных, и если объединение в текущий момент содержит одну из этих структур, то
- на общую часть данных разрешается ссылаться через любую из указанных структур.
- Так, правомерен следующий фрагмент программы:
- \begin{LongCodePar}
- union {
- struct {
- int type;
- } n;
- struct {
- int type;
- int intnode;
- } ni;
- struct {
- int type;
- float floatnode;
- } nf;
- } u;
- ...
- u.nf.type = FLOAT;
- u.nf.floatnode = 3.14;
- ...
- if (u.n.type == FLOAT)
- ... sin(u.nf.floatnode) ...
- \end{LongCodePar}
- \subsection{Перечисления}
- \label{apx:subsec:enumerations}
- \index{константа!перечисления|(}%
- \index{перечисление!константа|(}%
- \index{перечисление!тег|(}%
- \index{перечислитель}%
- \index{спецификатор!enum@\texttt{enum}}%
- \index{тег!перечисления|(}%
- Перечисления -- это уникальный тип, значения которого покрываются множеством
- именованных констант, называемых перечислителями. Вид спецификатора перечисления
- заимствован у структур и объединений.
- \begin{ShortGramDecsWithCC}{\\\[\]}
- \textit[переч-спецификатор:]
- enum \textit[идентификатор\textsubscript[необ]]\
- { \textit[список-перечислителей] }
- enum \textit[идентификатор]
- \textit[список-перечислителей:]
- \textit[перечислитель]
- \textit[список-перечислителей] , \textit[перечислитель]
- \textit[перечислитель:]
- \textit[идентификатор]
- \textit[идентификатор] = \textit[константное-выражение]
- \end{ShortGramDecsWithCC}
- \noindent Идентификаторы, входящие в список перечислителей, объявляются
- константами типа \verb|int| и могут употребляться везде, где требуется
- константа. Если в этом списке нет ни одного перечислителя со знаком \verb|=|, то
- значения констант начинаются с $0$ и увеличиваются на $1$ по мере чтения
- декларации слева направо. Перечислитель со знаком \verb|=| даёт соответствующему
- идентификатору значение; последующие идентификаторы продолжают прогрессию от
- заданного значения.
- Имена перечислителей, используемые в одной области действия, должны отличаться
- друг от друга и от имён обычных переменных, однако их значения могут и
- совпадать.
- Роль идентификатора в \textit{переч-спецификаторе} аналогична роли тега
- структуры в \textit{структ-спецификаторе}: он является именем некоторого
- конкретного перечисления. Правила для списков и \textit{переч-спецификаторов} (с
- тегами и без) те же, что и для спецификаторов структур или объединений, с той
- лишь оговоркой, что элементы перечислений не бывают незавершённого типа; тег
- \textit{переч-спецификатора} без списка перечислителей должен отсылать в
- пределах области действия на спецификатор со списком.
- \begin{ApxComment}
- В первом издании языка перечислений не было, но они уже несколько лет
- применяются.
- \end{ApxComment}
- \index{тег!перечисления|)}%
- \index{перечисление!тег|)}%
- \index{перечисление!константа|)}%
- \index{константа!перечисления|)}%
- \subsection{Деклараторы}
- \label{apx:subsec:declarators}
- \index{декларатор|(}%
- Деклараторы имеют следующий синтаксис:
- \begin{LongGramDecsWithCC}{\\\{\}}
- \textit{декларатор:}
- \textit{указатель\textsubscript{необ}} \textit{собственно-декларатор}
- \textit{собственно-декларатор:}
- \textit{идентификатор}
- ( \textit{декларатор} )
- \textit{собственно-декларатор}\
- [ \textit{константное-выражение\textsubscript{необ}} ]
- \textit{собственно-декларатор}\
- ( \textit{список-типов-параметров} )
- \textit{собственно-декларатор}\
- ( \textit{список-идентификаторов\textsubscript{необ}} )
- \textit{указатель:}
- * \textit{список-квалификаторов-типа\textsubscript{необ}}
- * \textit{список-квалификаторов-типа\textsubscript{необ}}\
- \textit{указатель}
- \textit{список-квалификаторов-типа:}
- \textit{квалификатор-типа}
- \textit{список-квалификаторов-типа} \textit{квалификатор-типа}
- \end{LongGramDecsWithCC}
- \noindent У структуры декларатора много сходных черт со структурой подвыражений,
- поскольку в деклараторе, как и в подвыражении, допускаются операции раскрытия
- указателя, обращения к функции и получения элемента массива (с тем же порядком
- применения).
- \subsection{Что означают деклараторы}
- \label{apx:subsec:what_declarators_mean}
- \index{декларация!типа}%
- \index{тип!декларация}%
- Список деклараторов располагается сразу после спецификаторов типа и указателя
- класса памяти. Главный элемент любого декларатора -- это объявляемый им
- идентификатор; в простейшем случае декларатор из одного его и состоит, что
- отражено в первой строке продукции грамматики с именем
- \textit{собственно-декларатор}. Спецификаторы класса памяти относятся
- непосредственно к идентификатору, а его тип зависит от вида декларатора.
- Декларатор следует воспринимать как утверждение: если в выражении идентификатор
- появляется в том же контексте, что и в деклараторе, то он обозначает объект
- специфицируемого типа.
- Если соединить спецификаторы декларации, относящиеся к
- типу~(\ref{apx:subsec:type_specifiers})‚ и некоторый конкретный декларатор, то
- декларация примет следующий вид: <<\verb|T D|>>, где \verb|T| -- тип, а \verb|D|
- -- декларатор. Эта запись описывает тип для идентификатора любого декларатора
- индуктивно.
- В декларации \verb|T D|, где \verb|D| -- просто идентификатор, тип
- идентификатора есть \verb|T|.
- В декларации \verb|T D|, где \verb|D| имеет вид
- \begin{ShortCodePar}
- ( D1 )
- \end{ShortCodePar}
- \noindent тип идентификатора в \verb|D1| тот же, что и в \verb|D|. Скобки не
- изменяют тип, но могут повлиять на результаты его <<привязки>> к идентификаторам
- в сложных деклараторах.
- \subsubsection{Деклараторы указателей}
- \index{декларация!указателя}%
- \index{структура!указатель на неё}%
- \index{указатель!декларация}%
- В декларации \verb|T D|, где \verb|D| имеет вид
- \begin{ShortGramDecsWithCC}{\\\{\}}
- * \textit{список-квалификаторов-типа\textsubscript{необ}} D1
- \end{ShortGramDecsWithCC}
- \noindent а тип идентификатора декларации \verb|T D1| есть
- <<\textit{модификатор-типа} \verb|T|>>, тип идентификатора \verb|D| есть
- <<\textit{модификатор-типа} \textit{список-квалификаторов-типа} указатель на
- \verb|T|>>. Квалификаторы, следующие за \verb|*|, относятся к самому указателю,
- а не к объекту, на который он указывает.
- Рассмотрим, например, декларацию
- \begin{ShortCodePar}
- int *ap[];
- \end{ShortCodePar}
- \noindent Здесь \verb|ap[]| играет роль \verb|D1|; декларацию
- <<\verb|int ap[]|>> следует расшифровать (см. ниже) как
- <<массив из \verb|int|>>; список квалификаторов типа здесь пуст, а модификатор
- типа есть <<массив из>>. Следовательно, на самом деле декларация \verb|ap|
- гласит: <<массив из указателей на \verb|int|>>.
- Вот ещё примеры деклараций:
- \begin{ShortCodePar}
- int i, *pi, *const cpi = &i;
- const int ci = 3, *pci;
- \end{ShortCodePar}
- \noindent В них объявляются целое \verb|i| и указатель на целое \verb|pi|.
- Значение указателя \verb|cpi| неизменно; \verb|cpi| всегда будет указывать в
- одно и то же место, даже если значение, на которое он ссылается, станет иным.
- Целое \verb|ci| есть константа, оно измениться не может (хотя может
- инициализироваться, как в данном случае). Тип указателя \verb|pci| произносится
- как <<указатель на \verb|const int|>>; сам указатель возможно изменить; при этом
- он будет ссылаться на другое место, но значение, на которое он будет указывать,
- посредством \verb|pci| изменить нельзя.
- \subsubsection{Деклараторы массивов}
- \label{apx:subsubsec:declarators_of_arrays}
- \index{массив!декларация}%
- \index{массив!декларатор}%
- \index{декларатор!массива}%
- \index{декларация!массива}%
- В декларации \verb|T D|, где \verb|D| имеет вид
- \begin{ShortGramDecsWithCC}{\\\{\}}
- D1 [ \textit{константное-выражение\textsubscript{необ}} ]
- \end{ShortGramDecsWithCC}
- \noindent и где тип идентификатора декларации \verb|T D1| есть
- <<\textit{модификатор-типа} \verb|T|>>, тип идентификатора \verb|D| есть
- <<\textit{модификатор-типа} массив из \verb|T|>>. Если константное выражение
- присутствует, то оно должно быть целочисленным и больше $0$. Если константное
- выражение, специфицирующее количество элементов в массиве, отсутствует, то
- массив имеет незавершённый тип.
- Массив можно конструировать из объектов арифметического типа, указателей,
- структур и объединений, а также других массивов (генерируя при этом многомерные
- массивы). Любой тип, из которого конструируется массив, должен быть завершённым,
- он не может быть, например, структурой или массивом незавершённого типа.
- \index{массив!многомерный}%
- Это значит, что для многомерного массива пустой может быть только первая
- размерность. Незавершённый тип массива получает своё завершение либо в другой
- декларации этого массива~(\ref{apx:subsec:external_declarations}), либо при его
- инициализации~(\ref{apx:subsec:initialization}). Например, запись
- \begin{ShortCodePar}
- float fa[17], *afp[17];
- \end{ShortCodePar}
- \noindent декларирует массив из \verb|float|-чисел и массив из указателей на
- \verb|float|-числа. Аналогично
- \begin{ShortCodePar}
- static int x3d[3][5][7];
- \end{ShortCodePar}
- \noindent декларирует статический трёхмерный массив целых размера
- $3\times5\times7$. На самом деле, если быть точными, \verb|x3d| является
- массивом из трёх элементов, каждый из которых есть массив из пяти элементов,
- содержащих по 7 целых.
- \index{массив!порядок элементов в памяти}%
- \index{индексирование массива}%
- \index{указатели!и индексирование}%
- Операция индексирования \verb|E1[E2]| определена так, что она идентична операции
- \verb|*(E1+E2)|. Следовательно, несмотря на асимметричность записи,
- индексирование -- коммутативная операция. Учитывая правила преобразования,
- применяемые для оператора \verb|+| и
- массивов~(\ref{apx:subsec:pointers_and_integers},~\ref{apx:subsec:generation_of_pointer},~\ref{apx:subsec:additive_operators}),
- можно сказать, что если \verb|E1| -- массив, а \verb|E2| -- целое, то
- \verb|E1[E2]| обозначает \verb|E2|-й элемент массива \verb|E1|.
- %
- % исправлена орфографическая ошибка
- % в оригинале было ``ассиметричность''
- %
- \index{индексирование массива!и указатели}%
- Так, \verb|x3d[i][j][k]| означает то же самое, что и \verb|*(x3d[i][j] + k)|.
- Первое подвыражение, \verb|x3d[i][j]|,
- согласно~\ref{apx:subsec:generation_of_pointer} приводится к типу <<указатель на
- массив целых>>; по~\ref{apx:subsec:additive_operators} сложение включает
- умножение на размер объекта типа \verb|int|. Из этих же правил следует, что
- массивы запоминаются <<построчно>> (последние индексы меняются чаще) и что
- первая размерность в декларации помогает определить количество памяти,
- занимаемой массивом, однако в вычислении адреса элемента массива участия не
- принимает.
- \subsubsection{Деклараторы функций}
- \label{apx:subsubsec:declarators_of_functions}
- \index{декларатор!функции}%
- \index{декларация!функции}%
- \index{список!аргументов переменной длины}%
- \index{функция}%
- \index{функция!декларация}%
- При новом способе декларация функции \verb|T D|, где \verb|D| имеет вид
- \begin{ShortGramDecsWithCC}{\\\{\}}
- D1(\textit{список-типов-параметров})
- \end{ShortGramDecsWithCC}
- \noindent и тип идентификатора декларации \verb|T D1| есть
- <<\textit{модификатор-типа} \verb|T|>>, тип идентификатора в \verb|D| есть
- <<\textit{модификатор-типа} функция с аргументами
- \textit{список-типов-параметров}, возвращающая \verb|T|>>.
- Параметры имеют следующий синтаксис:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{список-типов-параметров:}
- \textit{список-параметров}
- \textit{список-параметров} , ...
- \textit{список-параметров:}
- \textit{декларация-параметра}
- \textit{список-параметров} , \textit{декларация-параметра}
- \textit{декларация-параметра:}
- \textit{спецификаторы-декларации} \textit{декларатор}
- \textit{спецификаторы-декларации}\
- \textit{абстрактный-декларатор\textsubscript{необ}}
- \end{ShortGramDecsWithCC}
- \noindent%
- \index{void@\texttt{void}!список аргументов}%
- При новом способе описания функций список параметров специфицирует их типы, а
- если функция вообще не имеет параметров, на месте списка типов указывается одно
- слово -- \verb|void|. Если список типов параметров заканчивается многоточием
- <<\verb|, ...|>>, то функция может иметь больше аргументов, чем число явно
- описанных параметров.~(См.~\ref{apx:subsubsec:function_call}.)
- Типы параметров, являющихся массивами и функциями, заменяются на указатели в
- соответствии с правилами преобразования
- параметров~(\ref{apx:subsec:definitions_of_functions}). Единственный
- спецификатор класса памяти, который разрешён в декларации параметра, -- это
- \verb|register|, однако он игнорируется, если декларатор функции не является
- заголовком её определения. Аналогично, если деклараторы в декларациях параметров
- содержат идентификаторы, а декларатор функции не является заголовком определения
- функции, то эти идентификаторы тотчас же выводятся из текущей области действия.
- При старом способе декларация функции \verb|T D|, где \verb|D| имеет вид
- \begin{ShortGramDecsWithCC}{\\\{\}}
- D1(\textit{список-идентификаторов\textsubscript{необ}})
- \end{ShortGramDecsWithCC}
- \noindent и тип идентификатора декларации \verb|T D1| есть
- <<\textit{модификатор-типа} \verb|T|>>, тип идентификатора в \verb|D| есть
- <<\textit{модификатор-типа} функция от неспецифицированных аргументов,
- возвращающая \verb|T|>>. Параметры, если они есть, имеют следующий вид:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{список-идентификаторов:}
- \textit{идентификатор}
- \textit{список-идентификаторов} , \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \noindent При старом способе, если декларатор функции не используется в качестве
- заголовка определения функции~(\ref{apx:subsec:definitions_of_functions}),
- список идентификаторов должен отсутствовать. Никакой информации о типах
- параметров в декларации не содержится.
- Например, декларация
- \begin{ShortCodePar}
- int f(), *fpi(), (*pfi)();
- \end{ShortCodePar}
- \noindent описывает функцию \verb|f|, возвращающую целое, функцию \verb|fpi|,
- возвращающую указатель на целое, и указатель \verb|pfi| на функцию, возвращающую
- целое. Ни для одной функции в декларации не указаны типы параметров; все функции
- описаны старым способом.
- Вот как выглядит декларация в новой записи:
- \begin{ShortCodePar}
- int strcpy(char *dest, const char *source), rand(void);
- \end{ShortCodePar}
- \noindent Здесь \verb|strcpy| -- функция с двумя аргументами,
- возвращающая значение типа \verb|int|; первый аргумент -- указатель на значение
- типа \verb|char|, а второй -- указатель на неизменяющееся значение типа
- \verb|char|. Имена параметров играют роль хороших комментариев. Вторая функция,
- \verb|rand|, аргументов не имеет и возвращает \verb|int|.
- \begin{ApxComment}
- Прототипы деклараторов функций с параметрами -- наиболее важное нововведение
- ANSI-стандарта. В сравнении со старым способом, принятым в первой редакции
- языка, они позволяют проверять и приводить к нужному типу аргументы во всех
- вызовах. Следует однако отметить, что их введение привнесло в язык некоторую
- сумятицу и необходимость согласования обеих форм. Чтобы обеспечить
- совместимость, потребовались некоторые <<синтаксические уродства>> типа
- \verb|void| для явного указания на отсутствие параметров.
- {\setlength{\parindent}{0.0604762\paperwidth}
- %
- % TODO: привести окружение в соответствие с требованиями данного блока
- %
- Многоточие <<\verb|, ...|>> применительно к функциям с варьируемым числом
- аргументов -- также новинка, которая вместе со стандартным головным файлом
- макросов \verb|<stdarg.h>| формализует неофициально используемый, но официально
- запрещённый в первой редакции механизм.
- Указанные способы записи заимствованы из языка Си++.
- }
- \end{ApxComment}
- \index{декларатор|)}%
- \index{декларация|)}%
- \subsection{Инициализация}
- \label{apx:subsec:initialization}
- \index{инициализатор|(}%
- \index{инициализация}%
- \index{инициализация!переменных!автоматических}%
- \index{инициализация!переменных!внешних}%
- \index{инициализация!переменных!статических}%
- При помощи \textit{иниц-декларатора} можно указать начальное значение
- декларируемого объекта.
- \index{фигурные скобки}%
- Инициализатору, представляющему собой выражение или список инициализаторов,
- заключённый в фигурные скобки, предшествует знак \verb|=|. Этот список может
- завершаться запятой; её назначение -- сделать форматирование более чётким.
- \begin{ShortGramDecsWithCC}{\\\[\]}
- \textit[инициализатор:]
- \textit[выражение-присваивания]
- { \textit[список-инициализаторов] }
- { \textit[список-инициализаторов] , }
- \textit[список-инициализаторов:]
- \textit[инициализатор]
- \textit[список-инициализаторов] , \textit[инициализатор]
- \end{ShortGramDecsWithCC}
- В инициализаторе статического объекта или массива все выражения должны быть
- константными~(\ref{apx:subsec:constant_expressions}). Если инициализатор
- \verb|auto|- и \verb|register|-объекта или массива находится в списке,
- заключённом в фигурные скобки, то входящие в него выражения также должны быть
- константными. Однако в случае автоматического объекта с одним выражением
- инициализатор не обязан быть константным выражением, он просто должен иметь тип,
- соответствующий объекту.
- \begin{ApxComment}
- В первой редакции не разрешалась инициализация автоматических структур,
- объединений и массивов. ANSI-стандарт позволяет это; однако, если инициализатор
- не может быть представлен одним простым выражением, инициализация может быть
- выполнена только при помощи константных конструкций.
- \end{ApxComment}
- \index{инициализация!по умолчанию}%
- \index{по умолчанию!инициализация}%
- Статический объект, инициализация которого явно не указана, инициализируется
- так, как если бы ему (или его членам) присваивалась константа $0$. Начальное
- значение автоматического объекта, явным образом не инициализированного, не
- определено.
- Инициализатор указателя или объекта арифметического типа -- это единичное
- выражение (возможно, заключённое в фигурные скобки), которое присваивается
- объекту.
- \index{инициализация!структуры}%
- \index{структура!инициализация|(}%
- Инициализатор структуры -- это либо выражение того же структурного типа, либо
- заключённые в фигурные скобки инициализаторы её членов, заданные по порядку.
- Безымянные поля битов игнорируются и не инициализируются. Если инициализаторов в
- списке меньше, чем членов, то оставшиеся члены инициализируются нулём.
- Инициализаторов не должно быть больше числа членов.
- \index{инициализация!массива}%
- Инициализатор массива -- это список инициализаторов его членов, заключённый в
- фигурные скобки. Если размер массива не известен, то он считается равным числу
- инициализаторов, при этом тип его становится завершённым. Если размер массива
- известен, то число инициализаторов не должно превышать числа его членов; если
- инициализаторов меньше, оставшиеся члены обнуляются.
- Как особый выделен случай инициализации массива литер. Последний можно
- инициализировать при помощи стрингового литерала; литеры инициализируют члены
- массива в том порядке, в каком они заданы в стринговом литерале. Точно так же,
- при помощи литерала из расширенного набора
- литер~(\ref{apx:subsec:string_literals})‚ можно инициализировать массив типа
- \verb|wchar_t|. Если размер массива не известен, то он определяется числом
- литер стринга, включающим и завершающую \verb|null|-литеру; если размер массива
- известен, то число литер стринга, не считая завершающей \verb|null|-литеры, не
- должно превышать его размера.
- \index{инициализация!объединения}%
- Инициализатором объединения может быть либо выражение того же типа, либо
- заключённый в фигурные скобки инициализатор его первого члена.
- \begin{ApxComment}
- В первой редакции не позволялось инициализировать объединения. Правило <<первого
- члена>> не отличается изяществом, однако не требует нового синтаксиса. Стандарт
- ANSI проясняет ещё и семантику не инициализируемых явно объединений.
- \end{ApxComment}
- \index{инициализация!структуры}%
- Введём для структуры и массива обобщённое имя: \emph{агрегат}. Если агрегат
- содержит члены агрегатного типа, то правила инициализации применяются
- рекурсивно. Фигурные скобки в некоторых случаях инициализации можно опускать.
- Если инициализатор члена агрегата, который сам является агрегатом, начинается с
- левой фигурной скобки, то этот подагрегат инициализируется последующим списком
- разделённых запятыми инициализаторов; считается ошибкой, если количество
- инициализаторов подагрегата превышает число его членов. Если, однако,
- инициализатор подагрегата не начинается с левой фигурной скобки, то, чтобы его
- инициализировать, нужно отсчитать соответствующее число элементов из списка; при
- этом остальные члены инициализируются следующими инициализаторами агрегата, для
- которого данный подагрегат является частью.
- \index{структура!инициализация|)}%
- Например,
- \begin{ShortCodePar}
- int x[] = { 1, 3, 5 };
- \end{ShortCodePar}
- \noindent декларирует и инициализирует \verb|x| как одномерный массив с тремя
- членами, поскольку размера указано не было, а список состоит из трёх
- инициализаторов.
- \index{инициализация!двухмерных массивов|(}%
- \index{массив!двумерный}%
- \begin{ShortCodePar}
- float y[4][3] = {
- { 1, 3, 5 },
- { 2, 4, 6 },
- { 3, 5, 7 },
- };
- \end{ShortCodePar}
- \noindent представляет собой инициализацию с полным набором фигурных скобок:
- $1$, $3$ и $5$ инициализируют первую строку в массиве \verb|y[0]|‚ т.е.
- \verb|y[0][0]|, \verb|y[0][1]| и \verb|y[0][2]|. Аналогично инициализируются
- следующие две строки: \verb|y[1]| и \verb|y[2]|. Инициализаторов не хватило на
- весь массив, поэтому элементы строки \verb|y[3]| будут нулевыми. В точности тот
- же результат был бы достигнут при помощи следующей декларации:
- \begin{ShortCodePar}
- float y[4][3] = {
- 1, 3, 5, 2, 4, 6, 3, 5, 7
- };
- \end{ShortCodePar}
- \noindent%
- \index{инициализация!массива}%
- Инициализатор для \verb|y| начинается с левой фигурной скобки, но для
- \verb|y[0]| скобки нет, поэтому из списка будут взяты три элемента. Аналогично
- по три элемента будут взяты для \verb|y[1]|, а затем и для \verb|y[2]|. В
- \begin{ShortCodePar}
- float y[4][3] = {
- { 1 }, { 2 }, { 3 }, { 4 }
- };
- \end{ShortCodePar}
- \noindent инициализируется первый столбец матрицы \verb|y|, все же другие
- элементы остаются нулевыми.
- \index{инициализация!двухмерных массивов|)}%
- \index{инициализация!стринговой константой}%
- Наконец,
- \begin{ShortCodePar}
- char msg[] = "Синтаксическая ошибка в строке %s\n";
- \end{ShortCodePar}
- \noindent представляет собой пример массива литер, члены которого
- инициализируются при помощи стринга; в его размере учитывается и завершающая
- \verb|null|-литера.
- \index{инициализатор|)}%
- \subsection{Имена типов}
- \label{apx:subsec:names_of_types}
- \index{декларатор!абстрактный}%
- \index{оператор!приведения к типу}%
- \index{тип!имя}%
- В ряде случаев возникает потребность в применении имени типа данных (например,
- при явном приведении к типу, в указании типов параметров внутри деклараций
- функций, в аргументе оператора \verb|sizeof|). Эта потребность реализуется при
- помощи \emph{имени типа}, определение которого синтаксически почти совпадает с
- декларацией объекта того же типа. Оно отличается от последней лишь тем, что не
- содержит имени объекта.
- {\setlength{\codeIndent}{\codeIndentBk-2.25em}
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{имя-типа:}
- \textit{список-спецификаторов-квалификаторов}\
- \textit{абстрактный-декларатор\textsubscript{необ}}
- \textit{абстрактный-декларатор:}
- \textit{указатель}
- \textit{указатель\textsubscript{необ}}\
- \textit{собственно-абстрактный-декларатор}
- \textit{собственно-абстрактный-декларатор:}
- ( \textit{абстрактный-декларатор} )
- \textit{собственно-абстрактный-декларатор\textsubscript{необ}}\
- [ \textit{константное-выражение\textsubscript{необ}} ]
- \textit{собственно-абстрактный-декларатор\textsubscript{необ}}\
- ( \textit{список-типов-параметров\textsubscript{необ}} )
- \end{ShortGramDecsWithCC}
- \setlength{\codeIndent}{\codeIndentBk}}
- \noindent Можно указать одно-единственное место в абстрактном деклараторе, где
- мог бы оказаться идентификатор, если бы приведённая конструкция была полноценным
- декларатором. Именованный тип совпадает с типом этого <<невидимого
- идентификатора>>. Например,
- \begin{ShortCodePar}
- int
- int *
- int *[3]
- int (*)[]
- int *()
- int (*[])(void)
- \end{ShortCodePar}
- \noindent соответственно обозначают типы <<целое>>, <<указатель на целое>>,
- <<массив из трёх указателей на целое>>, <<указатель на массив из неизвестного
- количества целых>>, <<функция неизвестного количества параметров, возвращающая
- указатель на целое>>, <<массив неизвестного количества указателей на функции без
- параметров, каждая из которых возвращает целое>>.
- \subsection{Декларация
- \texorpdfstring{\protect\Verb|typedef|}{typedef}}
- \label{apx:subsec:typedef_declaration}
- \index{декларация!typedef@\texttt{typedef}}%
- \index{typedef-декларация@\texttt{typedef}-декларация}%
- Декларации, в которых спецификатор класса памяти есть \verb|typedef|, не
- декларируют объекты -- они определяют идентификаторы, представляющие собой имена
- типов. Эти идентификаторы называются \textit{typedef-именами}.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{typedef-имя:}
- \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \noindent Декларация \verb|typedef| приписывает тип каждому имени своего
- декларатора обычным способом.~(См.~\ref{apx:subsec:what_declarators_mean}.) С
- этого момента \textit{typedef-имя} синтаксически эквивалентно ключевому слову
- спецификатора типа, обозначающему связанный с ним тип. Например, после
- \begin{ShortCodePar}
- typedef long Blockno, *Blockptr;
- typedef struct { double r, theta; } Complex;
- \end{ShortCodePar}
- %
- % исправлена опечатка
- % в оригинале одна левая скобка была круглой
- %
- \noindent допустимы следующие декларации:
- \begin{ShortCodePar}
- Blockno b;
- extern Blockptr bp;
- Complex z, *zp;
- \end{ShortCodePar}
- \noindent Тип \verb|b| есть \verb|long|, тип \verb|bp| -- <<указатель на
- \verb|long|>>, тип \verb|z| -- структура заданного вида, а \verb|zp| --
- указатель на такую структуру.
- Декларация \verb|typedef| не вводит новых типов, она только даёт имена типам,
- которые могли бы быть специфицированы и другим способом. Например, \verb|b|
- имеет тот же тип, что и любой другой \verb|long|-объект.
- \textit{Typedef-имена} могут быть перекрыты другими определениями во внутренней
- области действия, но при условии, что в них присутствует указание типа.
- Например,
- \begin{ShortCodePar}
- extern Blockno;
- \end{ShortCodePar}
- \noindent не переопределяет \verb|Blockno|‚ а вот
- \begin{ShortCodePar}
- extern int Blockno;
- \end{ShortCodePar}
- \noindent переопределяет.
- \subsection{Эквивалентность типов}
- \label{apx:subsec:type_equvalency}
- \index{тип!эквивалентность}%
- \index{эквивалентность типов}%
- Два списка спецификаторов типа эквивалентны, если они содержат одинаковый их
- набор с учётом синонимичности названий (например, \verb|long| и \verb|long int|
- считаются одинаковыми типами). Структуры, объединения и перечисления с разными
- тегами считаются разными, а каждое безтеговое объединение, структура или
- перечисление представляет собой уникальный тип.
- Два типа считаются совпадающими, если их абстрактные
- деклараторы~(\ref{apx:subsec:names_of_types}) после замены всех
- \textit{typedef-имён} их типами и выбрасывания имён параметров функций составят
- эквивалентные списки спецификаторов типов. При сравнении учитываются размеры
- массивов и типы параметров функций.
- \section{Инструкции}
- \index{инструкции|(}%
- \index{инструкции!последовательность выполнения}%
- \index{порядок!выполнения инструкций}%
- За исключением оговорённых случаев инструкции выполняются в том порядке, как они
- написаны. Инструкции не имеют значений и выполняются, чтобы произвести
- определённые действия. Все виды инструкций можно разбить на несколько групп:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{инструкция:}
- \textit{помеченная-инструкция}
- \textit{инструкция-выражение}
- \textit{составная-инструкция}
- \textit{инструкция-выбора}
- \textit{циклическая-инструкция}
- \textit{инструкция-перехода}
- \end{ShortGramDecsWithCC}
- \subsection{Помеченные инструкции}
- \label{apx:subsec:labeled_instructions}
- \index{метка!case@\texttt{case}}%
- \index{метка!default@\texttt{default}}%
- \index{метка}%
- \index{инструкция!помеченная}%
- \index{case-метка@\texttt{case}-метка}%
- \index{default@\texttt{default}}%
- Инструкции может предшествовать метка.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{помеченная-инструкция:}
- \textit{идентификатор} : \textit{инструкция}
- case \textit{константное-выражение} : \textit{инструкция}
- default : \textit{инструкция}
- \end{ShortGramDecsWithCC}
- \noindent Метка, состоящая из идентификатора, одновременно служит и декларацией
- этого идентификатора. Единственное назначение идентификатора-метки -- указать
- место перехода для \verb|goto|.
- \index{метка!область действия}%
- \index{область действия!меток}%
- Областью действия идентификатора-метки является текущая функция. Так как метки
- имеют своё собственное пространство имён, они не <<конфликтуют>> с другими
- идентификаторами и не могут быть
- перекрыты.~(См.~\ref{apx:subsec:lexical_scope}.)
- \verb|case|-метки и \verb|default|-метки используются в инструкции
- \verb|switch|~(\ref{apx:subsec:choice_instruction}). Константное выражение в
- \verb|case| должно быть целочисленным.
- Сами по себе метки не изменяют порядка вычислений.
- \subsection{Инструкция-выражение}
- \label{apx:subsec:statement-expression}
- \index{выражение-инструкция}%
- \index{точка с запятой}%
- Наиболее употребительный вид инструкции -- это \textit{инструкция-выражение}.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{инструкция-выражение:}
- \textit{выражение\textsubscript{необ}} ;
- \end{ShortGramDecsWithCC}
- \noindent Чаще всего \textit{инструкция-выражение} -- это присваивание или
- вызов функции. Все действия, реализующие побочный эффект выражения,
- завершаются, прежде чем начинает выполняться следующая инструкция.
- \index{инструкция!пустая}%
- Если выражение в инструкции опущено, то она называется пустой; пустая инструкция
- часто используется для обозначения пустого тела циклической инструкции или в
- качестве места для метки.
- \subsection{Составная инструкция}
- \label{apx:subsec:composit_instruction}
- \index{блок}%
- \index{блок!структура}%
- \index{составная инструкция}%
- \index{инструкция!составная}%
- \index{фигурные скобки}%
- Так как в местах, где по синтаксису полагается одна инструкция, иногда возникает
- необходимость выполнить несколько, предусматривается возможность задания
- составной инструкции (которую также называют блоком). Тело определения функции
- есть составная инструкция:
- \begin{ShortGramDecsWithCC}{\\\[\]}
- \textit[составная-инструкция:]
- { \textit[список-деклараций\textsubscript[необ]]\
- \textit[список-инструкций\textsubscript[необ]] }
- \textit[список-деклараций:]
- \textit[декларация]
- \textit[список-деклараций] \textit[декларация]
- \textit[список-инструкций:]
- \textit[инструкция]
- \textit[список-инструкций] \textit[инструкция]
- \end{ShortGramDecsWithCC}
- \noindent%
- \index{блок!структура}%
- Если идентификатор из списка деклараций находился в области действия объемлющего
- блока, то действие внешней декларации при входе внутрь данного блока
- приостанавливается~(\ref{apx:subsec:lexical_scope})‚ а после выхода из него
- возобновляется. Внутри блока идентификатор может быть декларирован только один
- раз. Для каждого отдельного пространства имён эти правила действуют
- независимо~(\ref{apx:sec:scope}); идентификаторы из разных пространств имён
- всегда различны.
- \index{блок!инициализация}%
- \index{инициализация!в блоке}%
- Инициализация автоматических объектов осуществляется при каждом входе в блок и
- продолжается по мере продвижения по деклараторам. При передаче управления внутрь
- блока инициализации не выполняются. Инициализации статических объектов
- осуществляются только один раз перед запуском программы.
- \subsection{Инструкции выбора}
- \label{apx:subsec:choice_instruction}
- \index{инструкции!выбора}%
- \index{if-else@\texttt{if-else}!инструкция}%
- \index{switch-инструкция@\texttt{switch}-инструкция}%
- Инструкции выбора осуществляют отбор одной из нескольких альтернатив,
- определяющих порядок выполнения инструкций.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{инструкция-выбора:}
- if ( \textit{выражение} ) \textit{инструкция}
- if ( \textit{выражение} ) \textit{инструкция} else \textit{инструкция}
- switch ( \textit{выражение} ) \textit{инструкция}
- \end{ShortGramDecsWithCC}
- Оба вида \verb|if|-инструкций содержат выражение, которое должно иметь
- арифметический тип или тип указателя. Сначала вычисляется выражение со всеми его
- побочными эффектами, результат сравнивается с $0$. В случае несовпадения с $0$
- выполняется первая подинструкция. В случае совпадения с $0$ для второго типа
- \verb|if| выполняется вторая подинструкция.
- \index{неоднозначность \texttt{if-else}}%
- \index{if-else@\texttt{if-else}!неоднозначность}%
- Связанная со словом \verb|else| неоднозначность разрешается тем, что слово
- \verb|else| соотносят с последней не имеющей \verb|else| \verb|if|-инструкцией‚
- расположенной в одном с этим \verb|else| блоке и на одном уровне вложенности
- блоков.
- Инструкция \verb|switch| вызывает передачу управления на одну из нескольких
- инструкций в зависимости от значения выражения, которое должно иметь
- целочисленный тип. Управляемая при помощи \verb|switch| подинструкция обычно
- составная. Любая инструкция внутри этой подинструкции может быть помечена одной
- или несколькими \verb|case|-метками~(\ref{apx:subsec:labeled_instructions}).
- Управляющее выражение подвергается целочисленному
- повышению~(\ref{apx:subsec:integral_promotion}),
- а \verb|case|-константы приводятся к повышенному типу. После такого
- преобразования никакие две \verb|case|-константы в одной инструкции
- \verb|switch| не должны иметь одинаковых значений. Со \verb|switch|-инструкцией
- может быть связано не более одной \verb|default|-метки. Конструкции
- \verb|switch| допускается вкладывать друг в друга; \verb|case| и
- \verb|default|-метки относятся к самой внутренней \verb|switch|-инструкции из
- тех, которые их содержат.
- Инструкция \verb|switch| выполняется следующим образом. Вычисляется выражение со
- всеми побочными эффектами, и результат сравнивается с каждой
- \verb|case|-константой. Если одна из \verb|case|-констант равна значению
- выражения, управление переходит на инструкцию с соответствующей
- \verb|case|-меткой. Если ни с одной из \verb|case|-констант нет совпадения,
- управление передаётся на инструкцию с \verb|default|-меткой, если такая имеется,
- в противном случае ни одна из подинструкций \verb|switch| не выполняется.
- \begin{ApxComment}
- В первой редакции требовалось, чтобы выражение и \verb|case|-константы в
- \verb|switch| были целого типа.
- \end{ApxComment}
- \subsection{Циклические инструкции}
- \index{циклические инструкции}%
- \index{do-инструкция@\texttt{do}-инструкция}%
- \index{for@\texttt{for}!инструкция}%
- \index{while@\texttt{while}!инструкция}%
- Циклические инструкции специфицируют циклы.
- {\setlength{\codeIndent}{\codeIndentBk-0.25em}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{циклическая-инструкция:}
- while ( \textit{выражение} ) \textit{инструкция}
- do \textit{инструкция} while ( \textit{выражение} )
- for ( \textit{выражение\textsubscript{необ}} ;\
- \textit{выражение\textsubscript{необ}} ;\
- \textit{выражение\textsubscript{необ}} ) \textit{инструкция}
- \end{ShortGramDecsWithCC}
- \setlength{\codeIndent}{\codeIndentBk}}
- В инструкциях \verb|while| и \verb|do| выполнение подинструкции повторяется до
- тех пор, пока значение выражения не станет нулём. Выражение должно иметь
- арифметический тип или тип указателя. В \verb|while| вычисление выражения со
- всеми побочными эффектами и проверка осуществляются перед каждым выполнением
- инструкции, а в \verb|do| -- после.
- В инструкции \verb|for| первое выражение вычисляется один раз, тем самым
- осуществляется инициализация цикла. На тип этого выражения никакие ограничения
- не накладываются. Второе выражение должно иметь арифметический тип или тип
- указателя; оно вычисляется перед каждой итерацией. Как только его значение
- становится равным $0$, \verb|for| прекращает свою работу. Третье выражение
- вычисляется после каждой итерации и, следовательно, выполняет повторную
- инициализацию цикла. Никаких ограничений на его тип нет. Побочные эффекты всех
- трёх выражений заканчиваются по завершении их вычислений. Если подинструкция не
- содержит в себе \verb|continue|, то
- \begin{ShortCodeParWithCC}{\\\{\}}
- for ( \textit{выражение1} ; \textit{выражение2} ; \textit{выражение3} )\
- \textit{инструкция}
- \end{ShortCodeParWithCC}
- \noindent эквивалентна конструкции
- \begin{ShortCodeParWithCC}{\\\[\]}
- \textit[выражение1] ;
- while ( \textit[выражение2] ) {
- \textit[инструкция]
- \textit[выражение3] ;
- }
- \end{ShortCodeParWithCC}
- Любое из трёх выражений цикла может быть опущено. Считается, что отсутствие
- второго выражения равносильно сравнению с ненулевой константой.
- \subsection{Инструкции перехода}
- \index{инструкции!перехода}%
- \index{break@\texttt{break}}%
- \index{continue@\texttt{continue}}%
- \index{goto-инструкция@\texttt{goto}-инструкция}%
- Инструкции перехода осуществляют безусловную передачу управления.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{инструкция-перехода:}
- goto \textit{идентификатор} ;
- continue ;
- break ;
- return \textit{выражение\textsubscript{необ}} ;
- \end{ShortGramDecsWithCC}
- В \verb|goto|-инструкции идентификатор должен быть
- меткой~(\ref{apx:subsec:labeled_instructions}), расположенной в текущей функции.
- Управление передаётся на помеченную инструкцию.
- Инструкцию \verb|continue| можно располагать только внутри цикла. Она вызывает
- переход к следующей итерации самого внутреннего содержащего её цикла. Говоря
- более точно, для каждой из конструкций
- \smallskip
- {\setlength{\LTleft}{\codeIndent-\tabcolsep}%
- \SetLenVarWithVal{\Thirdlen}{(\linewidth-\LTleft-5\tabcolsep)/3}%
- \noindent\hspace{\LTleft}\begin{tabular}
- {p{\Thirdlen}p{\Thirdlen}p{\Thirdlen}}
- \verb|while (...) {|&\verb|do {|&\verb|for (...) {|\\
- \verb| ...|&\verb| ...|&\verb| ...| \\
- \verb|contin: ;|&\verb|contin: ;|&\verb|contin: ;| \\
- \verb|}|&\verb|} while (...);|&\verb|}|
- \end{tabular}}
- \smallskip
- \noindent инструкция \verb|continue|‚ если она не <<погружена>> в ещё более
- внутренний цикл, делает то же самое, что и \verb|goto contin|.
- Инструкция \verb|break| встречается в циклической или в
- \verb|swhitch|-инструкции, и только в них. Она завершает работу самой внутренней
- циклической или \verb|switch|-инструкции, содержащей \verb|break|, после чего
- управление переходит к следующей инструкции.
- \index{return-инструкция@\texttt{return}-инструкция}%
- При помощи \verb|return| функция возвращает управление в программу, откуда она
- была вызвана.
- \index{преобразование!\texttt{return}-инструкцией}%
- \index{тип!преобразование в \texttt{return}}%
- \index{return@\texttt{return}!преобразование типа в}%
- Если за \verb|return| следует выражение, то его значение возвращается вызвавшей
- эту функцию программе. Значение выражения приводится к типу так, как если бы оно
- присваивалось переменной, имеющей тот же тип, что и функция.
- Ситуация, когда <<путь>> вычислений приводит в конец функции (т.е. на последнюю
- закрывающую фигурную скобку), равносильна выполнению \verb|return|-инструкции
- без выражения. В последнем случае, а также в случае явного задания \verb|return|
- без выражения возвращаемое значение не определено.
- \index{инструкции|)}%
- \section{Внешние декларации}
- \label{apx:sec:external_declarations}
- \index{декларация!внешняя|(}%
- \index{декларация!внешней переменной}%
- \index{транслируемая компонента}%
- То, что подготовлено в качестве ввода для Си-компилятора, называется компонентой
- трансляции. Она состоит из последовательности внешних деклараций, каждая из
- которых представляет собой либо декларацию, либо определение функции.
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{компонента-трансляции:}
- \textit{внешняя-декларация}
- \textit{компонента-трансляции} \textit{внешняя-декларация}
- \textit{внешняя-декларация:}
- \textit{определение-функции}
- \textit{декларация}
- \end{ShortGramDecsWithCC}
- Область действия внешних деклараций простирается до конца компоненты трансляции,
- в которой они декларированы, точно так же, как
- \index{составная инструкция}%
- \index{инструкция!составная}%
- область действия деклараций в блоке распространяется до конца этого блока.
- Синтаксис внешней декларации не отличается от синтаксиса любой другой декларации
- за одним исключением: код функции можно определять только при помощи внешней
- декларации.
- \subsection{Определение функции}
- \label{apx:subsec:definitions_of_functions}
- \index{определение!функции}%
- \index{функция!определение}%
- Определение функции имеет следующий вид:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{определение-функции:}
- \textit{спецификаторы-декларации\textsubscript{необ}}\
- \textit{декларатор}
- \textit{список-деклараций\textsubscript{необ}}\
- \textit{составная-инструкция}
- \end{ShortGramDecsWithCC}
- \noindent Из спецификаторов класса памяти в \textit{спецификаторах-декларации}
- возможны только \verb|extern| и \verb|static|; различия между последними
- рассматриваются в~\ref{apx:subsec:links}.
- Типом возвращаемого функцией значения может быть арифметический тип, структура,
- объединение, указатель и \verb|void|, но не <<функция>> и не <<массив>>.
- Декларатор в декларации функции должен явно указывать на то, что описываемый им
- идентификатор имеет тип <<функция>>, т.е. он должен иметь одну из следующих двух
- форм~(\ref{apx:subsubsec:declarators_of_functions}):
- \begin{ShortGramDecsWithCC}{\\\{\}}
- \textit{собственно-декларатор} ( \textit{список-типов-параметров} )
- \textit{собственно-декларатор}\
- ( \textit{список-идентификаторов\textsubscript{необ}} )
- \end{ShortGramDecsWithCC}
- \noindent где \textit{собственно-декларатор} есть идентификатор или
- идентификатор, заключённый в скобки. Заметим, что на тип <<функция>> посредством
- \verb|typedef| ссылаться нельзя.
- Первая форма соответствует определению функции новым способом, для которого
- характерно декларирование параметров в \emph{списке-типов-параметров} вместе с
- их типами; \textit{список-деклараций}, располагаемый за декларатором, должен
- отсутствовать.
- \index{void@\texttt{void}!список аргументов}%
- Если \textit{список-типов-параметров} не состоит из одного-единственного слова
- \verb|void|, показывающего, что параметров у функции нет, то в каждом
- деклараторе в \textit{списке-типов-параметров} обязан присутствовать
- идентификатор.
- \index{список!аргументов переменной длины}%
- Если \textit{список-типов-параметров} заканчивается знаками <<\verb|, ...|>>, то
- вызов функции может иметь аргументов больше, чем параметров; в таком случае,
- чтобы ссылаться на дополнительные аргументы, следует пользоваться механизмом
- макроса \verb|va_arg| из головного файла \verb|<stdarg.h>|, описанного в
- приложении~\ref{apx:stdlib}. Функции с переменным числом аргументов должны иметь
- по крайней мере один именованный параметр.
- Вторая форма -- определение функции старым способом.
- \textit{Список-идентификаторов} содержит имена параметров, а
- \textit{список-деклараций} приписывает им типы. В \textit{списке-деклараций}
- разрешено декларировать только именованные параметры, инициализация запрещается,
- и из спецификаторов класса памяти возможен только \verb|register|.
- И в том и другом способе определения функции мыслится, что все параметры как бы
- декларированы в самом начале составной инструкции, образующей тело функции, и
- совпадающие с ними имена здесь декларироваться не должны (хотя, как и любые
- идентификаторы, их можно переопределить в более внутренних блоках). Декларацию
- параметра <<массив из \textit{тип}>> можно трактовать как <<указатель на
- \textit{тип}>>; аналогично декларацию параметра <<функция, возвращающая
- \textit{тип}>> -- как <<указатель на функцию, возвращающую \textit{тип}>>. В
- момент вызова функции её аргументы соответствующим образом преобразуются и
- присваиваются параметрам.~(См.~\ref{apx:subsubsec:function_call}.).
- \begin{ApxComment}
- Новый способ определения функций введён ANSI-стандартом. Есть также небольшие
- изменения в операции повышения типа; в первой редакции параметры типа
- \verb|float| следовало читать как \verb|double|. Различие между \verb|float| и
- \verb|double| становилось заметным, лишь когда внутри функции генерировался
- указатель на параметр.
- \end{ApxComment}
- Ниже приведён пример определения функции новым способом:
- \begin{ShortCodePar}
- int max(int a, int b, int c)
- {
- int m;
- m = (a > b) ? a : b;
- return (m > c) ? m : c;
- }
- \end{ShortCodePar}
- \noindent Здесь \verb|int| -- \textit{спецификаторы-декларации};
- \verb|max(int a, int b, int c)| -- декларатор функции, а \verb|{ ... }| -- блок,
- задающий её код. Определение старым способом той же функции выглядит следующим
- образом:
- \begin{ShortCodePar}
- int max(a, b, c)
- int a, b, c;
- {
- /* ... */
- }
- \end{ShortCodePar}
- \noindent где \verb|max(a, b, c)| -- декларатор, а \verb|int a, b, c| --
- \textit{список-деклараций} для параметров.
- \subsection{Внешние декларации}
- \label{apx:subsec:external_declarations}
- Внешние декларации специфицируют характеристики объектов, функций и других
- идентификаторов. Термин <<внешний>> здесь используется, чтобы подчеркнуть тот
- факт, что декларации расположены вне функций; впрямую с ключевым словом
- \verb|extern| (<<внешний>>) он не связан. Класс памяти для объекта с внешней
- декларацией либо вообще не указывается, либо специфицируется как \verb|extern|
- или \verb|static|.
- \index{транслируемая компонента}%
- В одной компоненте трансляции для одного идентификатора может содержаться
- несколько внешних деклараций, если они согласуются друг с другом по типу и
- способу связи и если для этого идентификатора существует не более одного
- определения.
- Две декларации объекта или функции считаются согласованными по типу в
- соответствии с правилами, рассмотренными в~\ref{apx:subsec:type_equvalency}.
- Кроме того, если декларации отличаются лишь тем, что в одной из них тип
- структуры, объединения или перечисления
- незавершён~(\ref{apx:subsec:declaration_of_structures_and_unions}), а в другой
- соответствующий ему тип с тем же тегом завершён, то такие типы считаются
- согласованными. Если два типа
- массива~(\ref{apx:subsubsec:declarators_of_arrays}) отличаются лишь тем, что
- один завершённый, а другой незавершённый, то такие типы также считаются
- согласованными. Наконец, если один тип специфицирует функцию старым способом, а
- другой -- ту же функцию новым способом (с декларациями параметров), то такие
- типы также считаются согласованными.
- \index{связь!внешняя}%
- \index{связь!внутренняя}%
- Если первая внешняя декларация функции или объекта помечена спецификатором
- \verb|static|, то у декларируемого идентификатора -- \emph{внутренняя связь}; в
- противном случае у него -- \emph{внешняя связь}. Способы связей обсуждаются
- в~\ref{apx:subsec:links}.
- Внешняя декларация объекта считается определением, если она имеет инициализатор.
- \index{определение!пробное}%
- \index{пробное определение}%
- Внешняя декларация, в которой нет инициализатора и нет спецификатора
- \verb|extern|, считается \emph{пробным определением}. Если в компоненте
- трансляции появится определение объекта, то все его пробные определения просто
- станут избыточными декларациями. Если никакого определения для этого объекта в
- компоненте трансляции не обнаружится, то все его пробные определения будут
- трактоваться как одно определение с инициализатором $0$.
- Каждый объект должен иметь ровно одно определение. Для объекта с внутренней
- связью это правило относится к каждой отдельной компоненте трансляции, поскольку
- объекты с внутренними связями в каждой компоненте уникальны. В случае объектов с
- внешними связями указанное правило действует в отношении всей программы в целом.
- \begin{ApxComment}
- Хотя правило одного определения формулируется несколько иначе по сравнению с
- первой редакцией, по существу оно совпадает с прежним. Некоторые реализации его
- ослабляют, более широко трактуя понятие пробного определения. В другом варианте
- указанного правила, который распространён в системах UNIX и признан как
- общепринятое расширение стандарта, все пробные определения объектов с внешними
- связями из всех транслируемых компонент программы рассматриваются вместе, а не
- отдельно в каждой компоненте. Если где-то в программе обнаруживается
- определение, то пробные определения становятся просто декларациями, но, если
- никакого определения не встретилось, то все пробные определения становятся
- одним-единственным определением с инициализатором $0$.
- \end{ApxComment}
- \index{декларация!внешняя|)}%
- \section{Область действия и связи}
- \label{apx:sec:scope}
- \index{компиляция!раздельная}%
- \index{область действия}%
- Каждый раз компилировать всю программу целиком нет необходимости. Исходный текст
- можно хранить в нескольких файлах, представляющих собой компоненты трансляции.
- Ранее скомпилированные программы могут загружаться из библиотек. Связи между
- функциями программы могут осуществляться через вызовы и внешние данные.
- Следовательно, существуют два вида областей действия: первая -- это
- \emph{лексическая область} идентификатора: т.е. область в тексте программы, где
- имеют смысл все его характеристики;
- \index{связь}%
- вторая область -- это область, ассоциируемая с объектами и функциями, имеющими
- внешние связи, устанавливаемые между идентификаторами из раздельно компилируемых
- компонент трансляции.
- \subsection{Лексическая область действия}
- \label{apx:subsec:lexical_scope}
- \index{лексическая область действия}%
- \index{область действия!лексическая}%
- \index{область действия!правила определения}%
- Каждый идентификатор попадает в одно из нескольких
- \index{именное пространство}%
- пространств имён. Эти пространства никак не связаны друг с другом. Один и тот же
- идентификатор может использоваться в разных смыслах даже в одной области
- действия, если он принадлежит разным пространствам имён. Ниже через точку с
- запятой перечислены классы объектов, имена которых представляют собой отдельные
- независимые пространства: объекты, функции, \verb|typedef|-имена и
- \verb|enum|-константы; метки инструкций; теги структур, объединений и
- перечислений; члены каждой отдельной структуры или объединения.
- \begin{ApxComment}
- Сформулированные правила несколько отличаются от прежних, описанных в первом
- издании. Метки инструкций не имели раньше собственного пространства; теги
- структур и теги объединений (а в некоторых реализациях и теги перечислений)
- имели отдельные пространства. Размещение тегов структур, объединений и
- перечислений в одном общем пространстве -- это дополнительное ограничение,
- которого раньше не было. Наиболее существенное отклонение от первой редакции в
- том, что каждая отдельная структура (или объединение) создаёт своё собственное
- пространство имён её членов. Таким образом, одно и то же имя может
- использоваться в нескольких различных структурах. Это правило широко применяется
- уже несколько лет.
- \end{ApxComment}
- %
- % в оригинале в левом нижнем углу страницы надпись ``8. Заказ № 13''
- %
- \index{область действия!внешних объектов}%
- \index{определение!внешней переменной}%
- Лексическая область действия идентификатора объекта (или функции), объявленного
- во внешней декларации, начинается с места, где заканчивается его декларатор, и
- простирается до конца компоненты трансляции, в которой он декларирован. Область
- действия параметра в определении функции начинается с начала блока,
- представляющего собой тело функции, и распространяется на всю функцию; область
- действия параметра в описании функции заканчивается в конце этого описания.
- \index{область действия!автоматических переменных}%
- Область действия идентификатора, декларируемого в начале блока, начинается от
- места, где заканчивается его декларатор, и продолжается до конца этого блока.
- \index{метка!область действия}%
- \index{область действия!меток}%
- Областью действия метки является вся функция, где эта метка встречается. Область
- действия тега структуры, объединения или перечисления начинается от его
- появления в спецификаторе типа и продолжается до конца компоненты трансляции для
- декларации внешнего уровня и до конца блока для декларации внутри функции.
- Если идентификатор явно декларирован в начале некоторого блока (в том числе тела
- функции), то любая декларация того же идентификатора, находящаяся снаружи этого
- блока, временно перестаёт действовать вплоть до конца блока.
- \subsection{Связи}
- \label{apx:subsec:links}
- \index{связь}%
- \index{связь!внешняя}%
- \index{связь!внутренняя}%
- Если встречается несколько деклараций, имеющих одинаковый идентификатор и
- описывающих объект (или функцию), то все эти декларации в случае внешней связи
- относятся к одному объекту (функции) -- уникальному для всей программы; если же
- связь внутренняя, то свойство уникальности распространяется только на компоненту
- трансляции.
- \index{static-переменные@\texttt{static}-переменные!внешние}%
- Как говорилось в~\ref{apx:subsec:external_declarations}‚ если первая внешняя
- декларация имеет спецификатор \verb|static|, то она описывает идентификатор с
- внутренней связью, если такого спецификатора нет, то с внешней связью. Если
- декларация находится внутри блока и не содержит \verb|extern|, то
- соответствующий идентификатор ни с чем не связан и уникален для данной функции.
- Если декларация содержит \verb|extern| и блок находится в области действия
- внешней декларации этого идентификатора, то последний имеет ту же связь и
- ссылается на тот же объект (функцию). Однако, если ни одной внешней декларации
- для этого идентификатора нет, то он имеет внешнюю связь.
- \section{Препроцессирование}
- \label{apx:sec:preprocessing}
- \index{макро-процессор|(}%
- \index{препроцессор|(}%
- Препроцессор выполняет макроподстановку, условную компиляцию, включение
- именованных файлов. Строки, начинающиеся со знака \verb|#| (перед которым
- возможны пробельные литеры), устанавливают связь с препроцессором.
- \index{транслируемая компонента}%
- Их синтаксис не зависит от остальной части языка; они могут появляться где
- угодно и оказывать влияние (независимо от области действия) вплоть до конца
- транслируемой компоненты. Границы строк принимаются во внимание; каждая строка
- анализируется отдельно (однако есть возможность <<склеивать>> строки,
- см.~\ref{apx:subsec:concatenation_of_strings}). Лексемами для препроцессора
- являются все лексемы языка и последовательности литер, задающие имена файлов,
- как, например, в директиве \verb|#include|~(\ref{apx:subsec:file_include}).
- Кроме того, любая литера, не определённая каким-либо другим способом,
- воспринимается как лексема. Влияние пробельных литер, отличающихся от пробелов и
- горизонтальных табуляций, внутри строк препроцессора не определено.
- \index{порядок!трансляции}%
- \index{трансляция!порядок}%
- \index{трансляция!фазы}%
- \index{фазы трансляции}%
- Само препроцессирование проистекает в нескольких логически последовательных
- фазах. В отдельных реализациях некоторые фазы объединены.
- \begin{enumerate}
- \item Трёхзнаковые последовательности, описанные
- в~\ref{apx:subsec:trigraph_sequences}‚ заменяются их эквивалентами.
- \index{литера!новая-строка \texttt{\textbackslash n}}%
- \index{n@\texttt{\textbackslash n}}%
- Между строками вставляются литеры новая-строка, если того требует
- операционная система.
- \item
- \index{литера!новая-строка \texttt{\textbackslash n}}%
- \index{n@\texttt{\textbackslash n}}%
- Выбрасываются пары литер, состоящие из обратной наклонной черты с последующей
- литерой новая-строка; тем самым осуществляется <<склеивание>>
- строк~(\ref{apx:subsec:concatenation_of_strings}).
- \item Программа разбивается на лексемы, разделённые литерами пропусков.
- \index{комментарий}%
- Комментарии заменяются на единичные пробелы. Затем выполняются директивы
- препроцессора и
- макроподстановки~(\ref{apx:subsec:macro_definition_and_expansion}--\ref{apx:subsec:predefined_names}).
- \item Эскейп-последовательности в литерных константах и стринговых
- литералах~(\ref{apx:subsubsec:character_constants}‚~\ref{apx:subsec:string_literals}) заменяются на литеры, которые они
- обозначают. Соседние стринговые литералы конкатенируются.
- \item Результат транслируется. Затем устанавливаются связи с другими
- программами и библиотеками посредством сбора необходимых программ и данных и
- соединения ссылок на внешние функции и объекты с их определениями.
- \end{enumerate}
- \subsection{Трёхзнаковые последовательности}
- \label{apx:subsec:trigraph_sequences}
- \index{литеры!набор!ASCII}%
- \index{литеры!набор}%
- \index{трёхзнаковые последовательности}%
- \index{ASCII}%
- Множество литер, из которых набираются исходные Си-программы, основано на
- семибитовом ASCII-коде.
- \index{литеры!набор!ISO 646-1983}%
- \index{ISO}%
- Однако он шире, чем инвариантный код литер ISO 646-1983 (ISO 646-1983 Invariant
- Code Set). Чтобы дать возможность пользоваться сокращённым набором литер, все
- указанные ниже трёхзнаковые последовательности заменяются на соответствующие им
- единичные литеры. Замена осуществляется до любой иной обработки.
- \begin{center}
- \begin{tabular}{lll}
- \verb|??= # |&\verb|??( [ |&\verb|??< { |\\
- \verb|??/ \ |&\verb|??) ] |&\verb|??> } |\\
- \verb|??' ^ |&\verb|??! | |&\verb|??- ~ |
- \end{tabular}
- \end{center}
- Никакие другие замены, кроме указанных, не делаются.
- \begin{ApxComment}
- Трёхзнаковые последовательности введены ANSI-стандартом.
- \end{ApxComment}
- \subsection{Склеивание строк}
- \label{apx:subsec:concatenation_of_strings}
- \index{склеивание строк}%
- \index{define@\texttt{{\#}define}!в несколько строк}%
- Строка, заканчивающаяся обратной наклонной чертой, соединяется со следующей,
- поскольку литера \verb|\| и следующая за ней литера новая-строка выбрасываются.
- Это делается перед <<разбиением>> текста на лексемы.
- \subsection{Макроопределение и макрорасширение}
- \label{apx:subsec:macro_definition_and_expansion}
- \index{макрос!расширение}%
- \index{определение!макроса}%
- \index{препроцессор!макрос|(}%
- \index{управляющая!строка|(}%
- \index{define@\texttt{{\#}define}}%
- Управляющая строка вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # define \textit{идентификатор} \textit{последовательность-лексем}
- \end{ShortGramDecsWithCC}
- %
- % в оригинале в левом нижнем углу страницы расположена надпись `` 8* ''
- %
- \noindent заставляет препроцессор заменять идентификатор на последовательность
- лексем; пробельные литеры в начале и в конце последовательности лексем
- выбрасываются. Повторная строка \verb|#define| с тем же идентификатором
- считается ошибкой, если последовательности лексем неидентичны (несовпадения в
- разделяющих пробельных литерах при сравнении во внимание не принимаются).
- \index{макрос!с аргументами}%
- \index{определение!макроса}%
- \index{define@\texttt{{\#}define}}%
- \index{define@\texttt{{\#}define}!с аргументами}%
- Строка вида
- {\setlength{\codeIndent}{0.25em}%
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # define \textit{идентификатор}( \textit{список-идентификаторов} )\
- \textit{последовательность-лексем}
- \end{ShortGramDecsWithCC}
- \setlength{\codeIndent}{\codeIndentBk}}
- \noindent где между первым идентификатором и знаком \verb|(| не должно быть ни
- одной пробельной литеры, представляет собой макроопределение с параметрами,
- задаваемыми списком идентификаторов. Как и в первом варианте, пробельные литеры
- в начале и в конце последовательности лексем выбрасываются, и макрос может быть
- повторно определён только с тем же списком параметров и той же
- последовательностью лексем.
- \index{undef@\texttt{{\#}undef}}%
- Управляющая строка вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # undef \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \noindent предписывает препроцессору <<забыть>> определение, данное
- идентификатору. Применение \verb|#undef| к неизвестному идентификатору ошибкой
- не считается.
- Если макроопределение было задано вторым способом, то текстуальная
- последовательность, состоящая из его идентификатора с, возможно, следующими за
- ним пробельными литерами, знака \verb|(|, списка лексем, разделённых занятыми, и
- знака \verb|)|, представляет собой вызов макроса.
- \index{лексема}%
- Аргументами вызова макроса являются лексемы, разделённые запятыми (запятые,
- <<закрытые>> кавычками или вложенными скобками, в разделении аргументов не
- участвуют). Аргументы при их выделении макрорасширениям не подвергаются.
- Количество аргументов в вызове макроса должно соответствовать количеству
- параметров макроопределения. После выделения аргументов окружающие и пробельные
- литеры выбрасываются. Затем в замещающей последовательности лексем макроса
- идентификаторы-параметры (если они не окружены кавычками) заменяются на
- соответствующие им аргументы. Если в замещающей последовательности перед
- параметром не стоит знак \verb|#| и ни перед ним, ни после него нет знака
- \verb|##|, то лексемы аргумента проверяются: не содержат ли они в себе
- макровызова, и если это так, то прежде чем аргумент будет подставлен,
- производится соответствующее ему макрорасширение.
- \index{лексема!подстановка}%
- \index{препроцессор!оператор \texttt{\#}}%
- На процесс подстановки влияют два специальных оператора. Первый -- это оператор
- \verb|#|, который ставится перед параметром. Он требует, чтобы подставляемый
- вместо параметра и знака \verb|#| (перед ним) текст был заключён в двойные
- кавычки. При этом в аргументе в стринговых литералах и литерных константах перед
- каждой двойной кавычкой \verb|"| (включая и обрамляющие стринг), а также перед
- каждой обратной наклонной чертой \verb|\| вставляется \verb|\|.
- \index{конкатенация!лексем}%
- \index{лексема!конкатенация}%
- \index{препроцессор!оператор \texttt{\#\#}}%
- Второй оператор записывается как \verb|##|. Если последовательность лексем в
- любого вида макроопределении содержит оператор \verb|##|, то сразу после
- подстановки параметров он вместе с окружающими его пробельными литерами
- выбрасывается, благодаря чему <<склеиваются>> соседние лексемы, образуя тем
- самым новую лексему. Результат не определён при получении неправильных лексем
- или когда генерируемый текст зависит от порядка применения операторов \verb|##|.
- Кроме того, \verb|##| не может стоять ни в начале, ни в конце замещающей
- последовательности лексем.
- В макросах обоих видов замещающая последовательность лексем повторно
- просматривается на предмет обнаружения там новых \verb|define|-имён. Однако,
- если некоторый идентификатор уже был заменён в данном расширении, повторное
- появление такого идентификатора не вызовет его замены.
- Если полученное расширение начинается со знака \verb|#|, оно не будет воспринято
- как директива препроцессора.
- \begin{ApxComment}
- ANSI-стандарт описывает процесс макрорасширения более точно, чем первое издание.
- Наиболее важные изменения касаются введения операторов \verb|#| и \verb|##|,
- которые предоставляют возможность осуществлять расширения внутри стрингов и
- конкатенацию лексем. Некоторые из новых правил, особенно касающиеся
- конкатенации, могут показаться несколько странными. (См. приведённые ниже
- примеры.)
- \end{ApxComment}
- Описанные возможности можно использовать для показа смысловой сущности констант,
- как, например, в
- \begin{ShortCodePar}
- #define TABSIZE 100
- int table[TABSIZE];
- \end{ShortCodePar}
- \noindent Определение
- \begin{ShortCodePar}
- #define ABSDIFF(a, b) ((a)>(b) ? (a)-(b) : (b)-(a))
- \end{ShortCodePar}
- \noindent задаёт макрос, возвращающий абсолютное значение разности его
- аргументов. В отличие от функции, делающей то же самое, аргументы и возвращаемое
- значение здесь могут иметь любой арифметический тип и даже быть указателями.
- Кроме того, аргументы, каждый из которых может иметь побочный эффект,
- вычисляются дважды: один раз -- при проверке, другой раз -- при вычислении
- результата.
- Если имеется определение
- \begin{ShortCodePar}
- #define tempfile(dir) #dir "/%s"
- \end{ShortCodePar}
- \noindent то макровызов \verb|tempfile(/usr/tmp)| даст в результате
- \begin{ShortCodePar}
- "/usr/tmp" "/%s"
- \end{ShortCodePar}
- \noindent Далее эти два стринга превратятся в один стринг. По макросу
- \begin{ShortCodePar}
- #define cat(x, y) x ## y
- \end{ShortCodePar}
- \noindent вызов \verb|cat(var, 123)| сгенерирует \verb|var123|. Однако
- \verb|cat(cat(1,2),3)| не даст желаемого, так как оператор \verb|##|
- воспрепятствует получению правильных аргументов для внешнего вызова \verb|cat|.
- В результате будет выдана следующая цепочка лексем:
- \begin{ShortCodePar}
- cat ( 1 , 2 )3
- \end{ShortCodePar}
- \noindent где \verb|)3| (результат <<склеивания>> последней лексемы первого
- аргумента с первой лексемой второго аргумента) не является правильной лексемой.
- Если второй уровень макроопределения задан в виде
- \begin{ShortCodePar}
- #define xcat(x,y) cat(x,y)
- \end{ShortCodePar}
- \noindent то никаких коллизий здесь не возникает; \verb|xcat(xcat(1,2),3)| в
- итоге даст \verb|123|, поскольку сам \verb|xcat| не использует \verb|##|.
- Аналогично сработает и \verb|ABSDIFF(ABSDIFF(a,b),c)|‚ и мы получим правильный
- результат.
- \subsection{Включение файла}
- \label{apx:subsec:file_include}
- \index{файл!включение}%
- \index{include@\texttt{{\#}include}}%
- Управляющая строка
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # include <\textit{имя-файла}>
- \end{ShortGramDecsWithCC}
- \noindent заменяется на содержимое файла с именем \textit{имя-файла}. Среди
- литер, составляющих \textit{имя-файла}, не должно быть знака \verb|>| и литеры
- новая-строка. Результат не определён, если \textit{имя-файла} содержит любую из
- литер \verb|"|, \verb|'|, \verb|\| или пару литер \verb|/*|. Порядок поиска
- указанного файла зависит от реализации.
- Подобным же образом выполняется управляющая строка
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # include "\textit{имя-файла}"
- \end{ShortGramDecsWithCC}
- \noindent Сначала поиск осуществляется по тем же правилам, по каким компилятор
- ищет первоначальный исходный файл (механизм этого поиска зависит от реализации),
- а в случае неудачи осуществляется методом поиска, принятым в \verb|#include|
- первого типа. Результат остаётся неопределённым, если имя файла содержит
- \verb|'|, \verb|\| или \verb|/*|; использование знака \verb|>| разрешается.
- Наконец, директива
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # include \textit{последовательность-лексем}
- \end{ShortGramDecsWithCC}
- \noindent не совпадающая ни с одной из предыдущих форм, рассматривает
- последовательность лексем как текст, который в результате всех макроподстановок
- должен дать \verb|#include| с \verb|<...>| или с \verb|"..."|. Сгенерированная
- таким образом директива далее будет интерпретироваться в соответствии с
- полученной формой.
- Файлы, вставляемые при помощи \verb|#include|, сами могут содержать в
- себе директивы \verb|#include|.
- \subsection{Условная компиляция}
- \label{apx:subsec:conditional_compilation}
- \index{условная компиляция}%
- \index{elif@\texttt{{\#}elif}}%
- \index{else a@\texttt{{\#}else}}%
- \index{endif@\texttt{{\#}endif}}%
- \index{if@\texttt{{\#}if}}%
- \index{ifdef@\texttt{{\#}ifdef}}%
- \index{ifndef@\texttt{{\#}ifndef}}%
- Части программы могут компилироваться условно, если они оформлены в соответствии
- со следующим схематично изображённым синтаксисом:
- \begin{LongGramDecsWithCC}{\\\{\}}
- \textit{условная-конструкция-препроцессора:}
- \textit{if-строка} \textit{текст} \textit{elif-части}\
- \textit{else-часть\textsubscript{необ}} #endif
- \textit{if-строка:}
- # if \textit{константное-выражение}
- # ifdef \textit{идентификатор}
- # ifndef \textit{идентификатор}
- \textit{elif-части:}
- \textit{elif-строка} \textit{текст}
- \textit{elif-части\textsubscript{необ}}
- \textit{elif-строка:}
- # elif \textit{константное-выражение}
- \textit{else-часть:}
- \textit{else-строка} \textit{текст}
- \textit{else-строка:}
- # else
- \end{LongGramDecsWithCC}
- \noindent Каждая из директив (\textit{if-строка}, \textit{elif-строка} и
- \verb|#endif|) записывается на отдельной строке. Константные выражения в
- \verb|#if| и последующих \verb|#elif|-строках вычисляются по порядку, пока не
- обнаружится выражение с ненулевым значением; текст, следующий за строкой с
- нулевым значением, выбрасывается. Текст, расположенный за директивой с ненулевым
- значением, обрабатывается обычным образом. Под словом <<текст>> здесь имеется в
- виду любая последовательность строк, включая строки препроцессора, которые не
- являются частью условной структуры; текст может быть и пустым. Если \verb|#if|
- или \verb|#elif|-строка с ненулевым значением выражения найдена и её текст
- обработан, то последующие \verb|#elif| и \verb|#else|-строки вместе со своими
- текстами выбрасываются. Если все выражения имеют нулевые значения и присутствует
- строка \verb|#else|, то следующий за ней текст обрабатывается обычным образом.
- Тексты <<неактивных>> ветвей условных конструкций, за исключением тех, которые
- заведуют вложенностью условных конструкций, игнорируются.
- \index{elif@\texttt{{\#}elif}}%
- \index{if@\texttt{{\#}if}}%
- Константные выражения в \verb|#if| и \verb|#elif| являются объектами для обычной
- макроподстановки.
- \index{препроцессор!оператор \texttt{defined}}%
- \index{defined@\texttt{defined}}%
- Более того, прежде чем просматривать выражения вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- defined \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \noindent и
- \begin{ShortGramDecsWithCC}{\\\{\}}
- defined ( \textit{идентификатор} )
- \end{ShortGramDecsWithCC}
- \noindent на предмет наличия в них макровызова, они заменяются на \verb|1L| или
- \verb|0L| в зависимости от того, был или не был определён препроцессором
- указанный в них идентификатор. Все идентификаторы, оставшиеся после
- макрорасширения, заменяются на \verb|0L|. Наконец, предполагается, что любая
- целая константа всегда имеет суффикс \verb|L|, т.е. вся арифметика имеет дело с
- операндами только типа \verb|long| или \verb|unsigned long|.
- Константное выражение~(\ref{apx:subsec:constant_expressions}) здесь используется
- с ограничениями: оно должно быть целочисленным, не может содержать в себе
- перечислимых констант, преобразований типа и операторов \verb|sizeof|.
- \index{ifdef@\texttt{{\#}ifdef}}%
- \index{ifndef@\texttt{{\#}ifndef}}%
- Управляющие строки
- \begin{ShortGramDecsWithCC}{\\\{\}}
- #ifdef \textit{идентификатор}
- #ifndef \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \noindent эквивалентны соответственно строкам
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # if defined \textit{идентификатор}
- # if ! defined \textit{идентификатор}
- \end{ShortGramDecsWithCC}
- \begin{ApxComment}
- Строки \verb|#elif| не было в первой редакции, хотя она и использовалась в
- некоторых препроцессорах. Оператор препроцессора \verb|defined| -- также новый.
- \end{ApxComment}
- \index{управляющая!строка|)}%
- \index{препроцессор!макрос|)}%
- \subsection{Нумерация строк}
- \index{line@\texttt{{\#}line}}%
- Для удобства работы с другими препроцессорами, генерирующими Си-программы, можно
- использовать одну из следующих директив:
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # line \textit{константа} "\textit{идентификатор}"
- # line \textit{константа}
- \end{ShortGramDecsWithCC}
- \noindent которая предписывает компилятору <<считать>>, что указанные десятичное
- целое и идентификатор являются номером следующей строки и именем текущего файла
- соответственно. Если имя файла отсутствует, то ранее запомненное имя не
- изменяется. Расширения макровызовов в \verb|line|-директиве выполняются до
- интерпретации последней.
- \subsection{Генерация сообщения об ошибке}
- \index{error@\texttt{{\#}error}}%
- Строка препроцессора вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # error \textit{последовательность-лексем\textsubscript{необ}}
- \end{ShortGramDecsWithCC}
- \noindent приказывает ему выдать диагностическое сообщение, включающее заданную
- последовательность лексем.
- \subsection{Прагма}
- \index{pragma@\texttt{{\#}pragma}}%
- Управляющая строка вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- # pragma \textit{последовательность-лексем\textsubscript{необ}}
- \end{ShortGramDecsWithCC}
- \noindent призывает препроцессор выполнить зависящие от реализации действия.
- Неопознанная прагма игнорируется.
- \subsection{Пустая директива}
- Строка препроцессора вида
- \begin{ShortGramDecsWithCC}{\\\{\}}
- #
- \end{ShortGramDecsWithCC}
- \noindent не вызывает никаких действий.
- \subsection{Заранее определённые имена}
- \label{apx:subsec:predefined_names}
- \index{препроцессор!заранее определённые имена}%
- Препроцессор <<понимает>> несколько заранее определённых идентификаторов; их он
- заменяет специальной информацией.
- \index{undef@\texttt{{\#}undef}}%
- Эти идентификаторы (и оператор препроцессора \verb|defined| в том числе) нельзя
- повторно переопределять, к ним нельзя также применять директиву \verb|#undef|.
- Это следующие идентификаторы:
- \begin{LongRtAlTab2cols}{0pt}{0pt}{\Verb|{\_}{\_}LINE{\_}{\_}|}
- \verb|__LINE__|%
- \index{препроцессор!заранее определённые имена!LINE@\texttt{\_\_LINE\_\_}}%
- \index{LINE a (имя для препроцессора)@\texttt{\_\_LINE\_\_} (имя для препроцессора)}%
- &Номер текущей строки исходного текста, десятичная константа.\\
- \verb|__FILE__|%
- \index{препроцессор!заранее определённые имена!FILE@\texttt{\_\_FILE\_\_}}%
- \index{FILE (имя для препроцессора)@\texttt{\_\_FILE\_\_} (имя для препроцессора)}%
- &Имя компилируемого файла, стринг.\\
- \verb|__DATE__|%
- \index{препроцессор!заранее определённые имена!DATE@\texttt{\_\_DATE\_\_}}%
- &Дата компиляции в виде \verb|"Ммм дд гггг"|, стринг.\\
- \verb|__TIME__|%
- \index{препроцессор!заранее определённые имена!TIME@\texttt{\_\_TIME\_\_}}%
- &Время компиляции в виде \verb|"чч:мм:сс"|‚ стринг.\\
- \verb|__STDC__|%
- \index{препроцессор!заранее определённые имена!STDC@\texttt{\_\_STDC\_\_}}%
- &Константа $1$. Предполагается, что этот идентификатор определён как $1$ только
- в тех реализациях, которые следуют стандарту.
- \end{LongRtAlTab2cols}
- \begin{ApxComment}
- Строки \verb|#error| и \verb|#pragma| впервые введены ANSI-стандартом. Заранее
- определённые макросы препроцессора также до сих пор не описывались, хотя и
- использовались в некоторых реализациях.
- \end{ApxComment}
- \index{препроцессор|)}%
- \index{макро-процессор|)}%
- \section{Грамматика}
- \label{apx:sec:grammar}
- Ниже приведены сведённые воедино грамматические правила, описанные в данном
- приложении. Они имеют то же содержание, но даны в ином порядке.
- Здесь не приводятся определения следующих терминальных символов:
- \textit{целая-константа}, \textit{литерная-константа},
- \textit{с-плав-точкой-константа}, \textit{идентификатор}, \textit{стринг} и
- \textit{перечислимая-константа}. Слова, набранные обычным латинским шрифтом, и
- знаки рассматриваются как терминальные символы и используются буквально в том
- виде, как записаны. Данную грамматику можно механически трансформировать в
- текст, понятный системе автоматической генерации грамматического распознавателя.
- Для этого помимо добавления некоторых синтаксических пометок, предназначенных
- для указания альтернативных продукций, потребуется расшифровка конструкции со
- словами <<один из>> и дублирование каждой продукции, использующей символ с
- индексом \textit{необ}, причём один вариант продукции должен быть написан с этим
- символом, а другой -- без него. С одним изменением, а именно удалением продукции
- \textit{typedef-имя: идентификатор} и объявлением \textit{typedef-имя}
- терминальным символом, данная грамматика будет понятна генератору
- грамматического распознавателя YACC.
- \index{неоднозначность \texttt{if-else}}%
- \index{if-else@\texttt{if-else}!неоднозначность}%
- Ей присуще лишь одно противоречие, вызываемое неоднозначностью
- \verb|if|-\verb|else|-конструкции.
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{компонента-трансляции:}
- \textit{внешняя-декларация}
- \textit{компонента-трансляции} \textit{внешняя-декларация}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{внешняя-декларация:}
- \textit{определение-функции}
- \textit{декларация}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{определение-функции:}
- \textit{спецификаторы-декларации\textsubscript{необ}} \textit{декларатор}
- \textit{список-деклараций\textsubscript{необ}}\
- \textit{составная-инструкция}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{декларация:}
- \textit{спецификаторы-декларации}\
- \textit{список-иниц-деклараторов\textsubscript{необ}};
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-деклараций:}
- \textit{декларация}
- \textit{список-деклараций} \textit{декларация}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{спецификаторы-декларации:}
- \textit{спецификатор-класса-памяти}\
- \textit{спецификаторы-декларации\textsubscript{необ}}
- \textit{спецификатор-типа}\
- \textit{спецификаторы-декларации\textsubscript{необ}}
- \textit{квалификатор-типа}\
- \textit{спецификаторы-декларации\textsubscript{необ}}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{спецификатор-класса-памяти:} один из
- auto register static extern typedef
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{спецификатор-типа:} один из
- void char short int long float double signed unsigned
- \textit{структ-или-объед-спецификатор}\
- \textit{enum-спецификатор} \textit{typedef-имя}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{квалификатор-типа:} один из
- const volatile
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{структ-или-объед-спецификатор:}
- \textit{структ-или-объед} \textit{идентификатор\textsubscript{необ}}\
- \{ \textit{список-структ-деклараций} \}
- \textit{структ-или-объед} \textit{идентификатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{структ-или-объед:} один из
- struct union
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-структ-деклараций:}
- \textit{структ-декларация}
- \textit{список-структ-деклараций} \textit{структ-декларация}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-иниц-деклараторов:}
- \textit{иниц-декларатор}
- \textit{список-иниц-деклараторов} , \textit{иниц-декларатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{иниц-декларатор:}
- \textit{декларатор}
- \textit{декларатор} = \textit{инициализатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{структ-декларация:}
- \textit{список-спецификаторов-квалификаторов}\
- \textit{список-структ-деклараторов} ;
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-спецификаторов-квалификаторов:}
- \textit{спецификатор-типа}\
- \textit{список-спецификаторов-квалификаторов\textsubscript{необ}}
- \textit{квалификатор-типа}\
- \textit{список-спецификаторов-квалификаторов\textsubscript{необ}}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-структ-деклараторов:}
- \textit{структ-декларатор}
- \textit{список-структ-деклараторов} , \textit{структ-декларатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{структ-декларатор:}
- \textit{декларатор}
- \textit{декларатор\textsubscript{необ}} : \textit{константное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{переч-спецификатор:}
- enum \textit{идентификатор\textsubscript{необ}}\
- \{ \textit{список-перечислителей} \}
- enum \textit{идентификатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-перечислителей:}
- \textit{перечислитель}
- \textit{список-перечислителей} , \textit{перечислитель}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{перечислитель:}
- \textit{идентификатор}
- \textit{идентификатор} = \textit{константное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{декларатор:}
- \textit{указатель\textsubscript{необ}} \textit{собственно-декларатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{собственно-декларатор:}
- \textit{идентификатор}
- ( \textit{декларатор} )
- \textit{собственно-декларатор}\
- [ \textit{константное-выражение\textsubscript{необ}} ]
- \textit{собственно-декларатор} ( \textit{список-типов-параметров} )
- \textit{собственно-декларатор}\
- ( \textit{список-идентификаторов\textsubscript{необ}} )
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{указатель:}
- * \textit{список-квалификаторов-типа\textsubscript{необ}}
- * \textit{список-квалификаторов-типа\textsubscript{необ}}\
- \textit{указатель}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-квалификаторов-типа:}
- \textit{квалификатор-типа}
- \textit{список-квалификаторов-типа} \textit{квалификатор-типа}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-типов-параметров:}
- \textit{список-параметров}
- \textit{список-параметров} , ...
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-параметров:}
- \textit{декларация-параметра}
- \textit{список-параметров} , \textit{декларация-параметра}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{декларация-параметра:}
- \textit{спецификаторы-декларации} \textit{декларатор}
- \textit{спецификаторы-декларации}\
- \textit{абстрактный-декларатор\textsubscript{необ}}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-идентификаторов:}
- \textit{идентификатор}
- \textit{список-идентификаторов} , \textit{идентификатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{инициализатор:}
- \textit{выражение-присваивания}
- \{ \textit{список-инициализаторов} \}
- \{ \textit{список-инициализаторов} , \}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-инициализаторов:}
- \textit{инициализатор}
- \textit{список-инициализаторов} , \textit{инициализатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{имя-типа:}
- \textit{список-спецификаторов-квалификаторов}\
- \textit{абстрактный-декларатор\textsubscript{необ}}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{абстрактный-декларатор:}
- \textit{указатель}
- \textit{указатель\textsubscript{необ}}\
- \textit{собственно-абстрактный-декларатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{собственно-абстрактный-декларатор:}
- ( \textit{абстрактный-декларатор} )
- \textit{собственно-абстрактный-декларатор\textsubscript{необ}}\
- [ \textit{константное-выражение\textsubscript{необ}} ]
- \textit{собственно-абстрактный-декларатор\textsubscript{необ}}\
- ( \textit{список-типов-параметров\textsubscript{необ}} )
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{typedef-имя:}
- \textit{идентификатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{инструкция:}
- \textit{помеченная-инструкция}
- \textit{инструкция-выражение}
- \textit{составная-инструкция}
- \textit{инструкция-выбора}
- \textit{циклическая-инструкция}
- \textit{инструкция-перехода}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{помеченная-инструкция:}
- \textit{идентификатор} : \textit{инструкция}
- case \textit{константное-выражение} : \textit{инструкция}
- default : \textit{инструкция}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{инструкция-выражение:}
- \textit{выражение\textsubscript{необ}} ;
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{составная-инструкция:}
- \{ \textit{список-декларации\textsubscript{необ}}\
- \textit{список-инструкции\textsubscript{необ}} \}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-инструкций:}
- \textit{инструкция}
- \textit{список-инструкций} \textit{инструкция}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{инструкция-выбора:}
- if ( \textit{выражение} ) \textit{инструкция}
- if ( \textit{выражение} ) \textit{инструкция}\
- else \textit{инструкция}
- switch ( \textit{выражение} ) \textit{инструкция}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{циклическая-инструкция:}
- while ( \textit{выражение} ) \textit{инструкция}
- do \textit{инструкция} while ( \textit{выражение} )
- for ( \textit{выражение\textsubscript{необ}} ;\
- \textit{выражение\textsubscript{необ}} ;\
- \textit{выражение\textsubscript{необ}} ) \textit{инструкция}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{инструкция-перехода:}
- goto \textit{идентификатор} ;
- continue ;
- break ;
- return \textit{выражение\textsubscript{необ}} ;
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{выражение:}
- \textit{выражение-присваивания}
- \textit{выражение} , \textit{выражение-присваивания}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{выражение-присваивания:}
- \textit{условное-выражение}
- \textit{унарное-выражение} \textit{оператор-присваивания}\
- \textit{выражение-присваивания}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{оператор-присваивания:} один из
- = *= /= %= += -= <<= >>= &= ^= |=
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{условное-выражение:}
- \textit{логическое-ИЛИ-выражение}
- \textit{логическое-ИЛИ-выражение} ?\
- \textit{выражение} : \textit{условное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{константное-выражение:}
- \textit{условное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{логическое-ИЛИ-выражение:}
- \textit{логическое-И-выражение}
- \textit{логическое-ИЛИ-выражение} || \textit{логическое-И-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{логическое-И-выражение:}
- \textit{ИЛИ-выражение}
- \textit{логическое-И-выражение} && \textit{ИЛИ-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{ИЛИ-выражение:}
- \textit{исключающее-ИЛИ-выражение}
- \textit{ИЛИ-выражение} | \textit{исключающее-ИЛИ-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{исключающее-ИЛИ-выражение:}
- \textit{И-выражение}
- \textit{исключающее-ИЛИ-выражение} ^ \textit{И-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{И-выражение:}
- \textit{выражение-равенства}
- \textit{И-выражение} & \textit{выражение-равенства}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{выражение-равенства:}
- \textit{выражение-отношения}
- \textit{выражение-равенства} == \textit{выражение-отношения}
- \textit{выражение-равенства} != \textit{выражение-отношения}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{выражение-отношения:}
- \textit{сдвиговое-выражение}
- \textit{выражение-отношения} < \textit{сдвиговое-выражение}
- \textit{выражение-отношения} > \textit{сдвиговое-выражение}
- \textit{выражение-отношения} <= \textit{сдвиговое-выражение}
- \textit{выражение-отношения} >= \textit{сдвиговое-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{сдвиговое-выражение:}
- \textit{аддитивное-выражение}
- \textit{сдвиговое-выражение} >> \textit{аддитивное-выражение}
- \textit{сдвиговое-выражение} << \textit{аддитивное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{аддитивное-выражение:}
- \textit{мультипликативное-выражение}
- \textit{аддитивное-выражение} + \textit{мультипликативное-выражение}
- \textit{аддитивное-выражение} - \textit{мультипликативное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{мультипликативное-выражение:}
- \textit{выражение-приведённое-к-типу}
- \textit{мультипликативное-выражение} *\
- \textit{выражение-приведённое-к-типу}
- \textit{мультипликативное-выражение} /\
- \textit{выражение-приведённое-к-типу}
- \textit{мультипликативное-выражение} %\
- \textit{выражение-приведённое-к-типу}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{выражение-приведённое-к-типу:}
- \textit{унарное-выражение}
- ( \textit{имя-типа} ) \textit{выражение-приведённое-к-типу}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{унарное-выражение:}
- \textit{постфиксное-выражение}
- ++ \textit{унарное-выражение}
- -- \textit{унарное-выражение}
- \textit{унарный-оператор} \textit{выражение-приведённое-к-типу}
- sizeof \textit{унарное-выражение}
- sizeof ( \textit{имя-типа} )
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{унарный-оператор:} один из
- & * + - ~ !
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{постфиксное-выражение:}
- \textit{первичное-выражение}
- \textit{постфиксное-выражение} [ \textit{выражение} ]
- \textit{постфиксное-выражение}\
- ( \textit{список-аргументов-выражений\textsubscript{необ}} )
- \textit{постфиксное-выражение} . \textit{идентификатор}
- \textit{постфиксное-выражение} -> \textit{идентификатор}
- \textit{постфиксное-выражение} ++
- \textit{постфиксное-выражение} --
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{первичное-выражение:}
- \textit{идентификатор}
- \textit{константа}
- \textit{стринг}
- ( \textit{выражение} )
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{список-аргументов-выражений:}
- \textit{выражение-присваивания}
- \textit{список-аргументов-выражений} , \textit{выражение-присваивания}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{константа:}
- \textit{целая-константа}
- \textit{литерная-константа}
- \textit{с-плав-точкой-константа}
- \textit{перечислимая-константа}
- \end{ShortGramDecsWithCCFinBlock}
- Грамматика языка препроцессора приводится в виде перечня структур управляющих
- строк. Для механического получения программы грамматического разбора она не
- годится. Грамматика включает символ \textit{текст}, который означает текст
- обычной программы, неусловные управляющие строки препроцессора и его законченные
- условные конструкции.
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{управляющая-строка:}
- # define \textit{идентификатор} \textit{последовательность-лексем}
- # define \textit{идентификатор}( \textit{идентификатор} , ... ,\
- \textit{идентификатор} )
- \
- \textit{последовательность-лексем}
- # undef \textit{идентификатор}
- # include <\textit{имя-файла}>
- # include "\textit{имя-файла}"
- # include \textit{последовательность-лексем}
- # line \textit{константа} "\textit{идентификатор}"
- # line \textit{константа}
- # error \textit{последовательность-лексем\textsubscript{необ}}
- # pragma \textit{последовательность-лексем\textsubscript{необ}}
- #
- \textit{условная-конструкция-препроцессора}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{условная-конструкция-препроцессора:}
- \textit{if-строка} \textit{текст} \textit{elif-части}\
- \textit{else-часть\textsubscript{необ}} # endif
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{if-строка:}
- # if \textit{константное-выражение}
- # ifdef \textit{идентификатор}
- # ifndef \textit{идентификатор}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{elif-части:}
- \textit{elif-строка} \textit{текст}
- \textit{elif-части\textsubscript{необ}}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{elif-строка:}
- # elif \textit{константное-выражение}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{else-часть:}
- \textit{else-строка} \textit{текст}
- \end{ShortGramDecsWithCCFinBlock}
- \begin{ShortGramDecsWithCCFinBlock}{\\\{\}}
- \textit{else-строка:}
- # else
- \end{ShortGramDecsWithCCFinBlock}
- %
- % проверить форматирование слов в тексте приложения
- % чтобы отсылки к грамматике были курсивом
- %
|