Керниган и Ритчи - Язык программирования Си (793773), страница 47
Текст из файла (страница 47)
Целые и числа с плавающей точкойПри преобразовании из типа с плавающей точкой в целочисленный дробная часть значения отбрасывается;если полученное при этом значение нельзя представить в заданном целочисленном типе, то результат неопределен. В частности, не определен результат преобразования отрицательных значений с плавающейточкой в беззнаковые целые.Если значение преобразуется из целого в величину с плавающей точкой и она находится в допустимомдиапазоне, но представляется в новом типе неточно, то результатом будет одно из двух значений новоготипа, ближайших к исходному. Если результат выходит за границы диапазона допустимых значений,поведение программы не определено.А 6.4. Типы с плавающей точкойПри преобразовании из типа с плавающей точкой меньшей точности в тип с плавающей точкой большейточности значение не изменяется.
Если, наоборот, переход осуществляется от большей точности к меньшей изначение остается в допустимых пределах нового типа, то результатом будет одно из двух ближайшихзначений нового типа. Если результат выходит за границы диапазона допустимых значений, поведениепрограммы не определено.14Integral promotion — целочисленное повышение — иногда также переводят как "интегральное продвижение".
—Примеч. ред.А 6.5. Арифметические преобразованияВо многих операциях преобразование типов операндов и определение типа результата осуществляются поодним и тем же правилам. Они состоят в том, что операнды приводятся к некоторому общему типу, которыйтакже является и типом результата. Эти правила называются обычными арифметическимипреобразованиями.Если какой-либо из операндов имеет тип long double, то другой приводится к long double.В противном случае, если какой-либо из операндов имеет тип double, то другой приводится кdouble.В противном случае, если какой-либо из операндов имеет тип float, то другой приводится к float.В противном случае для обоих операндов осуществляется целочисленное повышение; затем, еслиодин из операндов имеет тип unsigned long int, той другой преобразуется в unsigned longint.В противном случае, если один из операндов принадлежит типу long int, а другой — unsignedint, то результат зависит от того, покрывает ли long int все значения unsigned int, и если этотак, то unsigned int приводится к long int; если нет, то оба операнда преобразуются вunsigned long int.В противном случае, если один из операндов имеет тип long int, то другой приводится к longint.В противном случае, если один из операндов — unsigned int, то другой приводится к unsignedint.В противном случае оба операнда имеют тип int.Здесь есть два изменения.
Во-первых, арифметика с операндами с плавающей точкой теперь можетпроизводиться с одинарной точностью, а не только с двойной; в первой редакции языка вся арифметика сплавающей точкой производилась с двойной точностью. Во-вторых, более короткий беззнаковый тип вкомбинации с более длинным знаковым типом не распространяет свойство беззнаковости на типрезультата; в первой редакции беззнаковый тип всегда доминировал. Новые правила немного сложнее,но до некоторой степени уменьшают вероятность появления неожиданных эффектов в комбинацияхзнаковых и беззнаковых величин. При сравнении беззнакового выражения со знаковым того же размеравсе же может возникнуть неожиданный результат.А 6.6. Указатели и целыеК указателю можно прибавлять (и вычитать из него) выражение целочисленного типа; последнее в этомслучае подвергается преобразованию, описанному в А7.7 при рассмотрении оператора сложения.К двум указателям на объекты одного типа, принадлежащие одному массиву, может применяться операциявычитания; результат приводится к целому посредством преобразования, описанного в А7.7 прирассмотрении оператора вычитания.Целочисленное константное выражение со значением 0 или оно же, но приведенное к типу void *, можетбыть преобразовано в указатель любого типа операторами приведения, присваивания и сравнения.Результатом будет NULL-указатель, который равен любому другому NULL-указателю того же типа, но неравен никакому указателю на реальный объект или функцию.Для указателей допускаются и другие преобразования, но в связи с ними возникает проблема зависимостирезультата от реализации.
Эти преобразования должны быть специфицированы явным операторомпреобразования типа или оператором приведения (А7.5 и А8.8).Указатель можно привести к целочисленному типу, достаточно большому для его хранения; требуемыйразмер зависит от реализации.
Функция преобразования также зависит от реализации.Объект целочисленного типа можно явно преобразовать в указатель. Если целое получено из указателя иимеет достаточно большой размер, это преобразование даст тот же указатель; в противном случае результатзависит от реализации.Указатель на один тип можно преобразовать в указатель на другой тип. Если исходный указатель ссылается наобъект, должным образом не выровненный по границам слов памяти, то в результате может произойтиошибка адресации. Если требования на выравнивание у нового типа меньше или совпадают с требованиямина выравнивание первоначального типа, то гарантируется, что преобразование указателя в другой тип иобратно его не изменит; понятие "выравнивание" зависит от реализации, однако в любой реализацииобъекты типа char предъявляют минимальные требования на выравнивание.
Как описано в А6.8, указательможет также преобразовываться в void * и обратно, значение указателя при этом не изменяется.Указатель может быть преобразован в другой указатель того же типа с добавлением или удалениемквалификаторов (А4.4, А8.2) того типа объекта, на который этот указатель показывает. Новый указатель,полученный добавлением квалификатора, имеет то же значение, но с дополнительными ограничениями,внесенными новыми квалификаторами.
Операция по удалению квалификатора у объекта приводит к тому,что восстанавливается действие его начальных квалификаторов, заданных в объявлении этого объекта.Наконец, указатель на функцию может быть преобразован в указатель на функцию другого типа. Вызовфункции по преобразованному указателю зависит от реализации; однако, если указатель еще разпреобразовать к его исходному типу, результат будет идентичен вызову по первоначальному указателю.А 6.7. Тип voidЗначение (несуществующее) объекта типа void никак нельзя использовать, его также нельзя явно или неявнопривести к типу, отличному от void.
Поскольку выражение типа void обозначает отсутствие значения, егоможно применять только там, где не требуется значения. Например, в качестве выражения-инструкции (А9.2)или левого операнда у оператора "запятая" (А7.18).Выражение можно привести к типу void операцией приведения типа. Например, применительно к вызовуфункции, используемому в роли выражения-инструкции, операция приведения к void явным образомподчеркивает тот факт, что результат функции отбрасывается.Тип void не фигурировал в первом издании этой книги, однако за прошедшее время сталобщеупотребительным.А 6.8.
Указатели на voidЛюбой указатель на объект можно привести к типу void * без потери информации. Если результатподвергнуть обратному преобразованию, то мы получим прежний указатель. В отличие от преобразованийуказатель-в-указатель (рассмотренных в А6.6), которые требуют явных операторов приведения к типу, вприсваиваниях и сравнениях указатель любого типа может выступать в паре с указателем типа void * безкаких-либо предварительных преобразований типа.Такая интерпретация указателей void * — новая; ранее роль обобщенного указателя отводиласьуказателю типа char *.
Стандарт ANSI официально разрешает использование указателей void *совместно с указателями других типов в присваиваниях и сравнениях; в иных комбинациях указателейстандарт требует явных преобразований типа.А 7. ВыраженияПриоритеты описываемых операторов имеют тот же порядок, что и пункты данного параграфа (от высших книзшим). Например, для оператора +, описанного в А7.7, термин "операнды" означает "выражения,определенные в А7.1 — А7.6".
В каждом пункте описываются операторы, имеющие одинаковый приоритет, иуказывается их ассоциативность (левая или правая). Приоритеты и ассоциативность всех операторовотражены в грамматике, приведенной в А13.Приоритеты и ассоциативность полностью определены, а вот порядок вычисления выражения не определенза некоторым исключением даже для подвыражений с побочным эффектом.
Это значит, что если вопределении оператора последовательность вычисления его операндов специально не оговаривается, то вреализации можно свободно выбирать любой порядок вычислений и даже чередовать правый и левыйпорядок. Однако любой оператор использует значения своих операндов в точном соответствии сграмматическим разбором выражения, в котором он встречается.Это правило отменяет ранее предоставлявшуюся свободу в выборе порядка выполнения операций,которые математически коммутативны и ассоциативны, но которые в процессе вычислений могуттаковыми не оказаться. Это изменение затрагивает только вычисления с плавающей точкой,выполняющиеся "на грани точности", и ситуации, когда возможно переполнение.В языке не определен контроль за переполнением, делением на нуль и другими исключительнымиситуациями, возникающими при вычислении выражения.
В большинстве существующих реализаций Си привычислении знаковых целочисленных выражений и присваивании переполнение игнорируется, но результаттаких вычислений не определен. Трактовки деления на нуль и всех исключительных ситуаций, связанных сплавающей точкой, могут не совпадать в разных реализациях; иногда для обработки исключительныхситуаций предоставляется нестандартная библиотечная функция.А 7.1. Генерация указателяЕсли тип выражения или подвыражения есть "массив из Т", где Т — некоторый тип, то значением этоговыражения является указатель на первый элемент массива, и тип такого выражения заменяется на тип"указатель на Т". Такая замена типа не делается, если выражение является операндом унарногооператора &, или операндом операций ++, --, sizeof, или левым операндом присваивания, илиоперандом оператора .















