Керниган и Ритчи - Язык программирования Си (793773), страница 48
Текст из файла (страница 48)
(точка). Аналогично, выражение типа "функция, возвращающая Т", кромеслучая, когда оно является операндом для &, преобразуется в тип "указатель на функцию,возвращающую Т".А 7.2. Первичные выраженияПервичные выражения — это идентификаторы, константы, строки и выражения в скобках.первичное-выражение:идентификаторконстантастрока(выражение)Идентификатор, если он был должным образом объявлен (о том, как это делается, речь пойдет ниже), —первичное выражение.
Тип идентификатора специфицируется в его объявлении. Идентификатор есть lvalue,если он обозначает объект (А5) арифметического типа либо объект типа "структура", "объединение" или"указатель".Константа — первичное выражение. Ее тип зависит от формы записи, которая была рассмотрена в А2.5.Строковый литерал — первичное выражение. Изначально его тип — "массив из char" ("массив изwchar_t" для строки символов расширенного набора), но в соответствии с правилом, приведенным в А7.1,указанный тип обычно превращается в "указатель на char" ("указатель на wchar_t") срезультирующим значением "указатель на первый символ строки".
Для некоторых инициализаторов такаязамена типа не делается. (См. А8.7.)Выражение в скобках — первичное выражение, тип и значение которого идентичны типу и значению этого жевыражения без скобок. Наличие или отсутствие скобок не влияет на то, является ли данное выражение lvalueили нет.А 7.3. Постфиксные выраженияВ постфиксных выражениях операторы выполняются слева направо.постфиксное-выражение:первичное-выражениепостфиксное-выражение [ выражение ]постфиксное-выражение ( список-аргументов-выраженийнеоб.
)постфиксное-выражение . идентификаторпостфиксное-выражение -> идентификаторпостфиксное-выражение ++постфиксное-выражение -список-аргументов-выражений:выражение-присваиваниесписок-аргументов-выражений , выражение-присваиваниеА 7.3.1. Обращение к элементам массиваПостфиксное выражение, за которым следует выражение в квадратных скобках, есть постфиксноевыражение, обозначающее обращение к индексируемому массиву. Одно из этих двух выражений должнопринадлежать типу "указатель на Т", где Т — некоторый тип, а другое — целочисленному типу; типрезультата индексирования есть Т. Выражение Е1[Е2] по определению идентично выражению*((Е1)+(Е2)).
Подробности см. в А8.6.2.А 7.3.2. Вызов функцииВызов функции есть постфиксное выражение (оно называется именующим выражением функции — functiondesignator), за которым следуют скобки, содержащие (возможно пустой) список разделенных запятымивыражений-присваиваний (А7.17), представляющих собой аргументы этой функции. Если постфиксноевыражение — идентификатор, не объявленный в текущей области видимости, то считается, что этотидентификатор как бы неявно описан объявлениемextern int идентификатор();помещенным в самом внутреннем блоке, содержащем вызов соответствующей функции. Постфиксноевыражение (после, возможно неявного, описания и генерации указателя, см. А7.1) должно иметь тип"указатель на функцию, возвращающую Т", где Т — тип возвращаемого значения.В первой версии языка для именующего выражения функции допускался только тип "функция", ичтобы вызвать функцию через указатель, требовался явный оператор *.
ANSI-стандарт поощряетпрактику некоторых существующих компиляторов, разрешающих иметь одинаковый синтаксис дляобращения просто к функции и обращения к функции, специфицированной указателем. Возможностьприменения старого синтаксиса остается.Термин аргумент используется для выражения, задаваемого в вызове функции; термин параметр — дляобозначения получаемого ею объекта (или его идентификатора) в определении или объявлении функции.Вместо этих понятий иногда встречаются термины "фактический аргумент (параметр)" и "формальныйаргумент (параметр)", имеющие те же смысловые различия.При вызове функции каждый ее аргумент копируется; передача аргументов осуществляется строго через ихзначения.
Функции разрешается изменять значения своих параметров, которые являются лишь копиямиаргументов-выражений, но эти изменения не могут повлиять на значения самих аргументов. Однако можнопередать указатель, чтобы позволить функции изменить значение объекта, на который указывает этотуказатель.Имеются два способа объявления функции. В новом способе типы параметров задаются явно и являютсячастью типа функции; такое объявление называется прототипом функции.
При старом способе типыпараметров не указываются. Способы объявления функций обсуждаются в А8.6.3 и А10.1.Если вызов находится в области видимости объявления, написанного по-старому, каждый его аргументподвергается операции повышения типа: для целочисленных аргументов осуществляется целочисленноеповышение (А6.1), а для аргументов типа float — преобразование в double. Если число аргументов несоответствует количеству параметров в определении функции или если типы аргументов после повышения несогласуются с типами соответствующих параметров, результат вызова не определен.
Критерийсогласованности типов зависит от способа определения функции (старого или нового). При старом способесравниваются повышенный тип аргумента в вызове и повышенный тип соответствующего параметра; приновом способе повышенный тип аргумента и тип параметра (без его повышения) должны быть одинаковыми.Если вызов находится в области видимости объявления, написанного по-новому, аргументы преобразуются,как если бы они присваивались переменным, имеющим типы соответствующих параметров прототипа. Числоаргументов должно совпадать с числом явно описанных параметров, если только список параметров незаканчивается многоточием (, ...). В противном случае число аргументов должно быть больше числапараметров или равно ему; "скрывающиеся" под многоточием аргументы подвергаются операцииповышения типа (так, как это было описано в предыдущем абзаце).
Если определение функции задано постарому, то типы параметров в прототипе, которые неявно присутствуют в вызове, должны соответствоватьтипам параметров в определении функции после их повышения.Эти правила особенно усложнились из-за того, что они призваны обслуживать смешанный способ(старого с новым) задания функций. По возможности его следует избегать.Очередность вычисления аргументов не определяется, в разных компиляторах она различна. Однакогарантируется, что аргументы и именующее выражение функции вычисляются полностью (включая ипобочные эффекты) до входа в нее. Любая функция допускает рекурсивное обращение.А 7.3.3. Обращение к структурамПостфиксное выражение, за которым стоит точка с последующим идентификатором, является постфикснымвыражением.
Выражение первого операнда должно быть структурой или объединением, а идентификатор —именем элемента структуры или объединения. Значение — именованный элемент структуры илиобъединения, а тип значения — тип элемента структуры или объединения. Выражение является lvalue, еслипервое выражение — lvalue и если тип второго выражения — не "массив".Постфиксное выражение, за которым стоит стрелка (составленная из знаков - и >) с последующимидентификатором, является постфиксным выражением. Выражение первого операнда должно бытьуказателем на структуру (объединение), а идентификатор — именем элемента структуры (объединения).Результат — именованный элемент структуры (объединения), на которую указывает указатель, а тип значения— тип элемента структуры (объединения); результат — lvalue, если тип не есть "массив".Таким образом, выражение E1->MOS означает то же самое, что и выражение (*Е1).MOS.
Структуры иобъединения рассматриваются в А8.3.В первом издании книги уже было приведено правило, по которому имя элемента должнопринадлежать структуре или объединению, упомянутому в постфиксном выражении. Там, однако,оговаривалось, что оно не является строго обязательным. Последние компиляторы и ANSI делают егообязательным.А 7.3.4.
Постфиксные операторы инкремента и декрементаПостфиксное выражение, за которым следует ++ или --, есть постфиксное выражение. Значением такоговыражения является значение его операнда. После того как значение было взято, операнд увеличивается (++)или уменьшается (--) на 1. Операнд должен быть lvalue; информация об ограничениях, накладываемых наоперанд, и деталях операций содержится в А7.7, где обсуждаются аддитивные операторы, и в А7.17, гдерассматривается присваивание. Результат инкрементирования или декрементирования не есть lvalue.А 7.4. Унарные операторыВыражения с унарными операторами выполняются справа налево.унарное-выражение:постфиксное-выражение++ унарное-выражение-- унарное-выражениеунарный-оператор выражение-приведенное-к-типуsizeof унарное-выражениеsizeof ( имя-типа )унарный-оператор: один из&*+~!А 7.4.1.
Префиксные операторы инкремента и декрементаУнарное выражение, перед которым стоит ++ или --, есть унарное выражение. Операнд увеличивается (++)или уменьшается (--) на 1.Значением выражения является значение его операнда после увеличения (уменьшения). Операнд всегдадолжен быть lvalue; информация об ограничениях на операнд и о деталях операции содержится в А7.7, гдеобсуждаются аддитивные операторы, и в А7.17, где рассматривается присваивание.
Результатинкрементирования и декрементирования не есть lvalue.А 7.4.2. Оператор получения адресаУнарный оператор & обозначает операцию получения адреса своего операнда. Операнд должен быть либоlvalue, не ссылающимся ни на битовое поле, ни на объект, объявленный как register, либо иметь тип"функция". Результат — указатель на объект (или функцию), адресуемый этим lvalue. Если тип операнда естьТ, то типом результата является "указатель на Т".А 7.4.3.
Оператор косвенного доступаУнарный оператор * обозначает операцию косвенного доступа (раскрытия указателя), возвращающую объект(или функцию), на который указывает ее операнд. Результат есть lvalue, если операнд — указатель на объектарифметического типа или на объект типа "структура", "объединение" или "указатель". Если тип выражения— "указатель на Т", то тип результата — Т.А 7.4.4. Оператор унарный плюсОперанд унарного + должен иметь арифметический тип, результат — значение операнда.














