Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


A6.1. Целочисленное повышение



Объект типа перечисление, символ, короткое целое, целое в битовом поле - все они со знаком или без могут использоваться в выражении там, где возможно применение целого. Если тип int позволяет " охватить" все значения исходного типа операнда, то операнд приводится к int, в противном случае он приводится к unsigned int. Эта процедура называется целочисленным повышением (Integral promotion – целочисленное повышение – иногда также переводят как " интегральное продвижение” – Примеч. ред.).

A6.2. Целочисленные преобразования

Любое целое приводится к некоторому заданному беззнаковому типу путем поиска конгруэнтного (т. е. имеющего то же двоичное представление) наименьшего неотрицательного значения и получения остатка от деления его на nmax + 1, где nmax - наибольшее число в этом беззнаковом типе. Для двоичного представления в дополнительном коде это означает либо выбрасывание лишних старших разрядов, если беззнаковый тип " уже" исходного типа, либо заполнение недостающих старших разрядов нулями (для значения без знака) или значением знака (для значения со знаком), если беззнаковый тип " шире" исходного.

В результате приведения любого целого к знаковому типу преобразуемое значение не меняется, если оно представимо в этом новом типе, и противном случае результат зависит от реализации.

A6.3. Целые и числа с плавающей точкой

При преобразовании из типа с плавающей точкой в целочисленный дробная часть значения отбрасывается; если полученное при этом значение нельзя представить в заданном целочисленном типе, то результат не определен. В частности, не определен результат преобразования отрицательных значений с плавающей точкой в беззнаковые целые.

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

A6.4. Типы с плавающей точкой

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

А6.5. Арифметические преобразования

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

· Если какой-либо из операндов имеет тип long double, то другой приводится к long double.

· В противном случае, если какой-либо из операндов имеет тип double, то другой приводится к double.

· В противном случае, если какой-либо из операндов имеет тип float, то другой приводится к float.

· В противном случае для обоих операндов осуществляется целочисленное повышение: затем, если один из операндов имеет тип unsigned long int, то и другой преобразуется в unsigned long int.

· В противном случае, если один из операндов принадлежит типу long int, а другой - unsigned int, то результат зависит от того, покрывает ли long int все значения unsigned int, и если это так, то unsigned int приводится к long int; если нет, то оба операнда преобразуются в unsigned long int.

· В противном случае, если один из операндов имеет тип long int, то другой приводится к long int.

· В противном случае, если один из операндов - unsigned int, то другой приводится к unsigned int.

· В противном случае оба операнда имеют тип int.

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

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". Такая замена не делается, если выражение является операндом унарного оператора &, или операндом операций ++, --, sizeof, или левым операндом присваивания, или операндом оператора. (точка). Аналогично, выражение типа " функция, возвращающая Т", кроме случая, когда оно является операндом для &, преобразуется в тип " указатель на функцию, возвращающую T".

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

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

первичное - выражение: идентификатор константа строка (выражение)

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

Константа - первичное выражение. Ее тип зависит от формы записи, которая была рассмотрена в A2.5.

Строковый литерал - первичное выражение. Изначально его тип - " массив из char" (" массив из wchar_t" для строки символов расширенного набора), но в соответствии с правилом, приведенным в A7.1, указанный тип обычно превращается в " указатель на char" (" указатель на wchar_t" ) с результирующим значением " указатель на первый символ строки". Для некоторых инициализаторов такая замена типа не делается. (см. A8.7)

Выражение в скобках - первичное выражение, тип и значение которого идентичны типу и значению этого же выражения без скобок. Наличие или отсутствие скобок не влияет на то, является ли данное выражение lvalue или нет.

A7.3. Постфиксные выражения

В постфиксных выражениях операторы выполняются слева направо.


Поделиться:



Последнее изменение этой страницы: 2017-03-14; Просмотров: 450; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.028 с.)
Главная | Случайная страница | Обратная связь