Чтение онлайн

ЖАНРЫ

Язык программирования Си. Издание 3-е, исправленное

Ритчи Деннис М.

Шрифт:

A6.6. Указатели и целые 

К указателю можно прибавлять (и вычитать из него) выражение целочисленного типа; последнее в этом случае подвергается преобразованию, описанному в A7.7 при рассмотрении оператора сложения.

К двум указателям на объекты одного типа, принадлежащие одному массиву, может применяться операция вычитания; результат приводится к целому посредством преобразования, описанного в A7.7 при рассмотрении оператора вычитания.

Целочисленное константное выражение со значением 0 или оно же, но приведенное к типу void *, может быть преобразовано в указатель любого типа операторами приведения, присваивания и сравнения. Результатом будет NULL-указатель, который равен любому другому NULL-указателю того же типа,

но не равен никакому указателю на реальный объект или функцию.

Для указателей допускаются и другие преобразования, но в связи с ними возникает проблема зависимости результата от реализации. Эти преобразования должны быть специфицированы явным оператором преобразования типа или оператором приведения (A7.5 и A8.8).

Указатель можно привести к целочисленному типу, достаточно большому для его хранения; требуемый размер зависит от реализации. Функция преобразования также зависит от реализации.

Объект целочисленного типа можно явно преобразовать в указатель. Если целое получено из указателя и имеет достаточно большой размер, это преобразование даст тот же указатель; в противном случае результат зависит от реализации.

Указатель на один тип можно преобразовать в указатель на другой тип. Если исходный указатель ссылается на объект, должным образом не выровненный по границам слов памяти, то в результате может произойти ошибка адресации. Если требования на выравнивание у нового типа меньше или совпадают с требованиями на выравнивание первоначального типа, то гарантируется, что преобразование указателя в другой тип и обратно его не изменит; понятие "выравнивание" зависит от реализации, однако в любой реализации объекты типа char предъявляют минимальные требования на выравнивание. Как описано в A6.8, указатель может также преобразовываться в void * и обратно, значение указателя при этом не изменяется.

Указатель может быть преобразован в другой указатель того же типа с добавлением или удалением квалификаторов (A4.4, A8.2) того типа объекта, на который этот указатель показывает. Новый указатель, полученный добавлением квалификатора, имеет то же значение, но с дополнительными ограничениями, внесенными новыми квалификаторами. Операция по удалению квалификатора у объекта приводит к тому, что восстанавливается действие его начальных квалификаторов, заданных в объявлении этого объекта.

Наконец, указатель на функцию может быть преобразован в указатель на функцию другого типа. Вызов функции по преобразованному указателю зависит от реализации; однако, если указатель еще раз преобразовать к его исходному типу, результат будет идентичен вызову по первоначальному указателю.

A6.7. Тип void

Значение (несуществующее) объекта типа void никак нельзя использовать, его также нельзя явно или неявно привести к типу, отличному от void. Поскольку выражение типа void обозначает отсутствие значения, его можно применять только там, где не требуется значения. Например, в качестве выражения- инструкции (A9.2) или левого операнда у оператора "запятая" (A7.18). Выражение можно привести к тину void операцией приведения типа. Например, применительно к вызову функции, используемому в роли выражения-инструкции, операция приведения к void явным образом подчеркивает тот факт, что результат функции отбрасывается.

Тип void не фигурировал в первом издании этой книги, однако за прошедшее время стал общеупотребительным.

А6.8. Указатели на void

Любой указатель на объект можно привести к типу void * без потери информации. Если результат подвергнуть обратному преобразованию, то мы получим прежний указатель. В отличие от преобразований указатель-в-указатель (рассмотренных в A6.6), которые требуют явных операторов приведения к типу, в присваиваниях и сравнениях указатель любого типа может выступать в паре с указателем типа void * без каких-либо предварительных

преобразований типа.

Такая интерпретация указателей void * - новая; ранее роль обобщенного указателя отводилась указателю типа char *. Стандарт ANSI официально разрешает использование указателей void * совместно с указателями других типов в присваиваниях и сравнениях; в иных комбинациях указателей стандарт требует явных преобразований типа.

A7. Выражения

Приоритеты описываемых операторов имеют тот же порядок, что и пункты данного параграфа (от высших к низшим). Например, для оператора +, описанного в A7.7, термин "операнды" означает "выражения, определенные в A7.1-A7.6". В каждом пункте описываются операторы, имеющие одинаковый приоритет, и указывается их ассоциативность (левая или правая). Приоритеты и ассоциативность всех операторов отражены в грамматике, приведенной в A13.

Приоритеты и ассоциативность полностью определены, а вот порядок вычисления выражения не определен за некоторым исключением даже для подвыражений с побочным эффектом. Это значит, что если в определении оператора последовательность вычисления его операндов специально не оговаривается, то в реализации можно свободно выбирать любой порядок вычислений и даже чередовать правый и левый порядок. Однако любой оператор использует значения своих операндов в точном соответствии с грамматическим разбором выражения, в котором он встречается.

Это правило отменяет ранее предоставлявшуюся свободу в выборе порядка выполнения операций, которые математически коммутативны и ассоциативны, но которые в процессе вычислений могут таковыми не оказаться. Это изменение затрагивает только вычисления с плавающей точкой, выполняющиеся "на грани точности", и ситуации, когда возможно переполнение.

В языке не определен контроль за переполнением, делением на нуль и другими исключительными ситуациями, возникающими при вычислении выражения. В большинстве существующих реализаций Си при вычислении знаковых целочисленных выражений и присваивании переполнение игнорируется, но результат таких вычислений не определен. Трактовки деления на нуль и всех исключительных ситуаций, связанных с плавающей точкой, могут не совпадать в разных реализациях; иногда для обработки исключительных ситуаций предоставляется нестандартная библиотечная функция.

A7.1. Генерация указателя 

Если тип выражения или подвыражения есть "массив из T", где T– некоторый тип, то значением этого выражения является указатель на первый элемент массива, и тип такого выражения заменяется на тип "указатель на T". Такая замена не делается, если выражение является операндом унарного оператора amp;, или операндом операций ++, -, sizeof, или левым операндом присваивания, или операндом оператора . (точка). Аналогично, выражение типа "функция, возвращающая Т", кроме случая, когда оно является операндом для&, преобразуется в тип "указатель на функцию, возвращающую T".

A7.2. Первичные выражения

Первичные выражения это идентификаторы, константы, строки и выражения в скобках.

первичное - выражение:

идентификатор

константа

строка

(выражение)

Идентификатор, если он был должным образом объявлен (о том, как это делается, речь пойдет ниже), - первичное выражение. Тип идентификатора специфицируется в его объявлении. Идентификатор есть lvalue, если он обозначает объект (A5) арифметического типа, либо объект типа "структура", "объединение" или "указатель".

Поделиться с друзьями: