Язык программирования Си. Издание 3-е, исправленное - Брайан Керниган
Шрифт:
Интервал:
Закладка:
Если вызов находится в области видимости объявления, написанного по-новому, аргументы преобразуются, как если бы они присваивались переменным, имеющим типы соответствующих параметров прототипа. Число аргументов должно совпадать с числом явно описанных параметров, если только список параметров не заканчивается многоточием (, ...). В противном случае число аргументов должно быть больше числа параметров или равно ему; "скрывающиеся" под многоточием аргументы подвергаются операции повышения типа (так, как это было описано в предыдущем абзаце). Если определение функции задано по-старому, то типы параметров в прототипе, которые неявно присутствуют в вызове, должны соответствовать типам параметров в определении функции после их повышения.
Эти правила особенно усложнились из-за того, что они призваны обслуживать смешанный способ (старого с новым) задания функций. По возможности его следует избегать.
Очередность вычисления аргументов не определяется, в разных компиляторах она различна. Однако гарантируется, что аргументы и именующее выражение функции вычисляются полностью (включая и побочные эффекты) до входа в нее. Любая функция допускает рекурсивное обращение.
A7.3.3. Обращение к структурам
Постфиксное выражение, за которым стоит точка с последующим идентификатором, является постфиксным выражением. Выражение первого операнда должно быть структурой или объединением, а идентификатор - именем элемента структуры или объединения. Значение - именованный элемент структуры или объединения, а тип значения - тип элемента структуры или объединения. Выражение является lvalue, если первое выражение - lvalue и если тип второго выражения - не "массив".
Постфиксное выражение, за которым стоит стрелка (составленная из знаков - и >) с последующим идентификатором, является постфиксным выражением. Выражение первого операнда должно быть указателем на структуру (объединение), а идентификатор - именем элемента структуры (объединения). Результат - именованный элемент структуры (объединения), на которую указывает указатель, а тип значения - тип элемента структуры (объединения); результат - lvalue, если тип не есть "массив".
Таким образом, выражение E1->MOS означает то же самое, что и выражение (*E1).MOS. Структуры и объединения рассматриваются в A8.3.
В первом издании книги уже было приведено правило, по которому имя элемента должно принадлежать структуре или объединению, упомянутому в постфиксном выражении. Там, однако, оговаривалось, что оно не является строго обязательным. Последние компиляторы и ANSI делают его обязательным.
A7.3.4. Постфиксные операторы инкремента и декремента
Постфиксное выражение, за которым следует ++ или --, есть постфиксное выражение. Значением такого выражения является значение его операнда. После того как значение было взято, операнд увеличивается (++) или уменьшается (--) на 1. Операнд должен быть lvalue; информация об ограничениях, накладываемых на операнд, и деталях операций содержится в A7.7, где обсуждаются аддитивные операторы, и в A7.17, где рассматривается присваивание. Результат инкрементирования или декрементирования не есть lvalue.
А7.4. Унарные операторы
Выражения с унарными операторами выполняются справа налево.
унарное-выражение:
постфиксное-выражение
++ унарное-выражение
-- унарное-выражение
унарный-оператор выражение-приведенное-к-типу
sizeof унарное-выражение
sizeof (имя-типа)
унарный-оператор: один из
& * + - ~ !
А7.4.1. Префиксные операторы инкремента и декремента
Унарное выражение, перед которым стоит ++ или --, есть унарное выражение. Операнд увеличивается (++) или уменьшается (--) на 1.
Значением выражения является значение его операнда после увеличения (уменьшения). Операнд всегда должен быть lvalue; информация об ограничениях на операнд и о деталях операции содержится в A7.7, где обсуждаются аддитивные операторы, и в A7.17, где рассматривается присваивание. Результат инкрементирования и декрементирования не есть lvalue.
A7.4.2. Оператор получения адреса
Унарный оператор & обозначает операцию получения адреса своего операнда. Операнд должен быть либо lvalue, не ссылающимся ни на битовое поле, ни на объект, объявленный как register, либо иметь тип "функция". Результат - указатель на объект (или функцию), адресуемый этим lvalue. Если тип операнда есть T, то типом результата является "указатель на T".
A7.4.3. Оператор косвенного доступа
Унарный оператор * обозначает операцию косвенного доступа (раскрытия указателя), возвращающую объект (или функцию), на который указывает ее операнд. Результат есть lvalue, если операнд - указатель на объект арифметического типа или на объект типа "структура", "объединение" или "указатель". Если тип выражения - "указатель на T", то тип результата - T.
A7.4.4. Оператор унарный плюс
Операнд унарного + должен иметь арифметический тип, результат - значение операнда. Целочисленный операнд подвергается целочисленному повышению. Типом результата является повышенный тип операнда.
Унарный + был добавлен для симметрии с унарным -.
A7.4.5. Оператор унарный минус
Операнд для унарного минуса должен иметь арифметический тип, результат - значение операнда с противоположным знаком. Целочисленный операнд подвергается целочисленному повышению. Отрицательное значение от беззнаковой величины вычисляется вычитанием из nmax+1 приведенного к повышенному типу операнда, где nmax - максимальное число повышенного типа; однако минус нуль есть нуль. Типом результата будет повышенный тип операнда.
A7.4.6. Оператор побитового отрицания
Операнд оператора ~ должен иметь целочисленный тип, результат - дополнение операнда до единиц по всем разрядам. Выполняется целочисленное повышение типа операнда. Если операнд беззнаковый, то результат получается вычитанием его значения из самого большого числа повышенного типа. Если операнд знаковый, то результат вычисляется посредством приведения "повышенного операнда" к беззнаковому типу, выполнения операции ~ и обратного приведения его к знаковому типу. Тип результата - повышенный тип операнда.
A7.4.7. Оператор логического отрицания
Операнд оператора ! должен иметь арифметический тип или быть указателем. Результат равен 1, если сравнение операнда с 0 дает истину, и равен 0 в противном случае. Тип результата - int.
A7.4.8. Оператор определения размера sizeof
Оператор sizeof дает число байтов, требуемое для хранения объекта того типа, который имеет его операнд. Операнд - либо выражение (которое не вычисляется), либо имя типа, записанное в скобках. Примененный к char оператор sizeof дает 1. Для массива результат равняется общему количеству байтов в массиве, для структуры или объединения - числу байтов в объекте, включая и байты- заполнители, которые понадобились бы, если бы из элементов составлялся массив. Размер массива из n элементов всегда равняется n, помноженному на размер отдельного его элемента. Данный оператор нельзя применять к операнду типа "функция", к незавершенному типу и к битовому полю. Результат - беззнаковая целочисленная константа: конкретный ее тип зависит от реализации. В стандартном заголовочном файле <stddef.h>(см. приложение B) этот тип определяется под именем size_t.
A7.5. Оператор приведения типа
Имя типа, записанное перед унарным выражением н скобках, вызывает приведение значения этого выражения к указанному типу.
выражение-приведенное-к-типу:
унарное-выражение
(имя-типа) выражение-приведенное-к-типу
Данная конструкция называется приведением. Имена типов даны в A8.8. Результат преобразований описан в A6. Выражение с приведением типа не является lvalue.
A7.6. Мультипликативные операторы
Мультипликативные операторы *, / и % выполняются слева направо.