Функции и структура программ
Другой пример преобразования char в int дает функция lower, преобразующая данную прописную букву в строчную. Если выступающий в качестве аргумента символ не является прописной буквой, то lower возвращает его неизменным. Приводимая ниже программа справедлива только для набора символов ASCII.
lower(c) /* convert c to lower case; ascii only */ int c; { if ( c >= 'a' && c <= 'z' ) return( c + '@' - 'a'); else /*@ Записано вместо 'a' строчного*/ return(c); }
Эта функция правильно работает при коде ASCII, потому что численные значения, соответствующие в этом коде прописным и строчным буквам, отличаются на постоянную величину, а каждый алфавит является сплошным - между а и z нет ничего, кроме букв. Это последнее замечание для набора символов ebcdic систем IBM 360/370 оказывается несправедливым, в силу чего эта программа на таких системах работает неправильно - она преобразует не только буквы.
При преобразовании символьных переменных в целые возникает один тонкий момент. Дело в том, что сам язык не указывает, должны ли переменным типа char соответствовать численные значения со знаком или без знака. Может ли при преобразовании char в int получиться отрицательное целое? К сожалению, ответ на этот вопрос меняется от машины к машине, отражая расхождения в их архитектуре. На некоторых машинах (PDP-11, например) переменная типа char, крайний левый бит которой содержит 1, преобразуется в отрицательное целое ("знаковое расширение"). На других машинах такое преобразование сопровождается добавлением нулей с левого края, в результате чего всегда получается положительное число.
определение языка "C" гарантирует, что любой символ из стандартного набора символов машины никогда не даст отрицательного числа, так что эти символы можно свободно использовать в выражениях как положительные величины. Но произвольные комбинации двоичных знаков, хранящиеся как символьные переменные на некоторых машинах, могут дать отрицательные значения, а на других положительные.
Наиболее типичным примером возникновения такой ситуации является случай, когда значение -1 используется в качестве EOF. Рассмотрим программу
Преобразования возникают и при присваиваниях; значение правой части преобразуется к типу левой, который и является типом результата. Символьные переменные преобразуются в целые либо со знаковым расширением ,либо без него, как описано выше. Обратное преобразование int в char ведет себя хорошо - лишние биты высокого порядка просто отбрасываются. Таким образом
int i; char c; i = c; c = i;
значение 'с' не изменяется. Это верно независимо от того, вовлекается ли знаковое расширение или нет.
Если х типа float, а i типа int, то как
х = i; так и i = х;
приводят к преобразованиям; при этом float преобразуется в int отбрасыванием дробной части. тип double преобразуется во float округлением. Длинные целые преобразуются в более короткие целые и в переменные типа char посредством отбрасывания лишних битов высокого порядка.
Так как аргумент функции является выражением, то при передаче функциям аргументов также происходит преобразование типов: в частности, char и short становятся int, а float становится double. Именно поэтому мы описывали аргументы функций как int и double даже тогда, когда обращались к ним с переменными типа CHAR и float.
Наконец, в любом выражении может быть осуществлено ("принуждено") явное преобразование типа с помощью конструкции, называемой перевод (cast). В этой конструкции, имеющей вид
(имя типа) выражение
Выражение преобразуется к указанному типу по правилам преобразования, изложенным выше. Фактически точный смысл операции перевода можно описать следующим образом: выражение как бы присваивается некоторой переменной указанного типа, которая затем используется вместо всей конструкции. Например, библиотечная процедура sqrt ожидает аргумента типа double и выдаст бессмысленный ответ, если к ней по небрежности обратятся с чем-нибудь иным. таким образом, если n - целое, то выражение
sqrt((double) n)
до передачи аргумента функции sqrt преобразует n к типу double. (Отметим, что операция перевод преобразует значение n в надлежащий тип; фактическое содержание переменной n при этом не изменяется). Операция перевода имеет тот же уровень старшинства, что и другие унарные операции, как указывается в таблице в конце этой лекции.
Упражнение 2-2
Составьте программу для функции htoi(s), которая преобразует строку шестнадцатеричных цифр в эквивалентное ей целое значение. При этом допустимыми цифрами являются цифры от 1 до 9 и буквы от а до F.