2.7. Преобразование типов
Если в выражениях встречаются операнды различных типов,
то они преобразуются к общему типу в соответствии с неболь-
шим набором правил. В общем, автоматически производятся
только преобразования, имеющие смысл, такие как, например,
преобразование целого в плавающее в выражениях типа F+I. Вы-
ражения же, лишенные смысла, такие как использование пере-
менной типа FLOAT в качестве индекса, запрещены.
Во-первых, типы CHAR и INT могут свободно смешиваться в
арифметических выражениях: каждая переменная типа CHAR авто-
матически преобразуется в INT. Это обеспечивает значительную
гибкость при проведении определенных преобразований симво-
лов. Примером может служить функция ATOI, которая ставит в
соответствие строке цифр ее численный эквивалент.
· 46 -
ATOI(S) /* CONVERT S TO INTEGER */
CHAR S[];
{
INT I, N;
N = 0;
FOR ( I = 0; S[I]>='0' && S[I]<='9'; ++I)
N = 10 * N + S[I] - '0';
RETURN(N);
}
KAK Уже обсуждалось в главе 1, выражение
S[I] - '0'
имеет численное значение находящегося в S[I] символа, потому
что значение символов '0', '1' и т.д. образуют возрастающую
последовательность расположенных подряд целых положительных
чисел.
Другой пример преобразования CHAR в INT дает функция
LOWER, преобразующая данную прописную букву в строчную. Если
выступающий в качестве аргумента символ не является пропис-
ной буквой, то LOWER возвращает его неизменным. Приводимая
ниже программа справедлива только для набора символов ASCII.
LOWER© /* CONVERT C TO LOWER CASE; ASCII ONLY */
INT C;
{
IF ( C >= 'A' && C <= 'Z' )
RETURN( C + '@' - 'A');
ELSE /*@ Записано вместо 'A' строчного*/
RETURN©;
}
Эта функция правильно работает при коде ASCII, потому что
численные значения, соответствующие в этом коде прописным и
строчным буквам, отличаются на постоянную величину, а каждый
алфавит является сплошным - между а и Z нет ничего, кроме
букв. Это последнее замечание для набора символов EBCDIC
систем IBM 360/370 оказывается несправедливым, в силу чего
эта программа на таких системах работает неправильно - она
преобразует не только буквы.
При преобразовании символьных переменных в целые возни-
кает один тонкий момент. Дело в том, что сам язык не указы-
вает, должны ли переменным типа CHAR соответствовать числен-
ные значения со знаком или без знака. Может ли при преобра-
зовании CHAR в INT получиться отрицательное целое? К сожале-
нию, ответ на этот вопрос меняется от машины к машине, отра-
жая расхождения в их архитектуре. На некоторых машинах
(PDP-11, например) переменная типа CHAR, крайний левый бит
которой содержит 1, преобразуется в отрицательное целое
(“знаковое расширение”). На других машинах такое преобразо-
вание сопровождается добавлением нулей с левого края, в ре-
зультате чего всегда получается положительное число.
· 47 -
Определение языка “C” гарантирует, что любой символ из
стандартного набора символов машины никогда не даст отрица-
тельного числа, так что эти символы можно свободно использо-
вать в выражениях как положительные величины. Но произволь-
ные комбинации двоичных знаков, хранящиеся как символьные
переменные на некоторых машинах, могут дать отрицательные
значения, а на других положительные.
Наиболее типичным примером возникновения такой ситуации
является сучай, когда значение 1 используется в качестве
EOF. Рассмотрим программу
CHAR C;
C = GETCHAR();
IF ( C == EOF )
...
На машине, которая не осуществляет знакового расширения,
переменная 'с' всегда положительна, поскольку она описана
как CHAR, а так как EOF отрицательно, то условие никогда не
выполняется. Чтобы избежать такой ситуации, мы всегда пре-
дусмотрительно использовали INT вместо CHAR для любой пере-
менной, получающей значение от GETCHAR.
Основная же причина использования INT вместо CHAR не
связана с каким-либо вопросом о возможном знаковом расшире-
нии. просто функция GETCHAR должна передавать все возможные
символы (чтобы ее можно было использовать для произвольного
ввода) и, кроме того, отличающееся значение EOF. Следова-
тельно значение EOF не может быть представлено как CHAR, а
должно храниться как INT.
Другой полезной формой автоматического преобразования
типов является то, что выражения отношения, подобные I>J, и
логические выражения, связанные операциями && и \!\!, по оп-
ределению имеют значение 1, если они истинны, и 0, если они
ложны. Таким образом, присваивание
ISDIGIT = C >= '0' && C <= '9';
полагает ISDIGIT равным 1, если с - цифра, и равным 0 в про-
тивном случае. (В проверочной части операторов IF, WHILE,
FOR и т.д. “Истинно” просто означает “не нуль”).
Неявные арифметические преобразования работают в основ-
ном, как и ожидается. В общих чертах, если операция типа +
или *, которая связывает два операнда (бинарная операция),
имеет операнды разных типов, то перед выполнением операции
“низший” тип преобразуется к “высшему” и получается резуль-
тат “высшего” типа. Более точно, к каждой арифметической
операции применяется следующая последовательность правил
преобразования.
· Типы CHAR и SHORT преобразуются в INT, а FLOAT в
DOUBLE.
·
48 -
· Затем, если один из операндов имеет тип DOUBLE, то
другой преобразуется в DOUBLE, и результат имеет тип DOUBLE.
· В противном случае, если один из операндов имеет тип LONG, то другой преобразуется в LONG, и результат имеет тип LONG.
· В противном случае, если один из операндов имеет тип UNSIGNED, то другой преобразуется в UNSIGNED и результат имеет тип UNSIGNED.
· В противном случае операнды должны быть типа INT, и
результат имеет тип INT.
Подчеркнем, что все переменные типа FLOAT в выражениях пре-
образуются в DOUBLE; в “C” вся плавающая арифметика выполня-
ется с двойной точностью.
Преобразования возникают и при присваиваниях; значение
правой части преобразуется к типу левой, который и является
типом результата. Символьные переменные преобразуются в це-
лые либо со знаковым расширением ,либо без него, как описано
выше. Обратное преобразование 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). В этой конструкции, имеющей
вид
(имя типа) выражение
· 49 -
Выражение преобразуется к указанному типу по правилам
преобразования, изложенным выше. Фактически точный смысл
операции перевода можно описать следующим образом: выражение
как бы присваивается некоторой переменной указанного типа,
которая затем используется вместо всей конструкции. Напри-
мер, библиотечная процедура SQRT ожидает аргумента типа
DOUBLE и выдаст бессмысленный ответ, если к ней по небреж-
ности обратятся с чем-нибудь иным. таким образом, если N -
целое, то выражение
SQRT((DOUBLE) N)
до передачи аргумента функции SQRT преобразует N к типу
DOUBLE. (Отметим, что операция перевод преобразует значение
N в надлежащий тип; фактическое содержание переменной N при
этом не изменяется). Операция перевода имрация перевода име-
ет тот же уровень старшинства, что и другие унарные опера-
ции, как указывается в таблице в конце этой главы.
Упражнение 2-2.
Составьте программу для функции HTOI(S), которая преоб-
разует строку шестнадцатеричных цифр в эквивалентное ей це-
лое значение. При этом допустимыми цифрами являются цифры от
... основаниям. При этом философская абстракция языка оказывается неразрывно связана с основными темами и движениями философии в целом. Более конкретно, на ранние стадии традиционно рассматриваемого в рамках АФ анализа обыденного языка глубокое влияние оказала философия Дж. Э. Мура, особенно его учение о здравом смысле, согласно которому такие понятия, как «человек», «мир», «я», «внешний мир», « ...
... и других странах СНГ, а также облегчение доступа к русской и мировой культуре и науке. Таким образом, судя по данным наших исследований, востребованность русского языка осталась в республике достаточно высокой. Многие представители современной молдавской молодежи продолжают, как их отцы и деды, тянуться к русской культуре, научным и техническим достижениям России. Русский язык остается языком ...
... рисуночное словесно-слоговое письмо). Памятники среднеэламского периода (14—12 вв. до н.э.) выполнены аккадской клинописью. Памятники новоэламского периода относятся к 8—6 вв. до н.э. Был официальным языком в персидском государстве Ахеменидов в 6—4 вв. предполагается, что он, подвергшись влиянию древнеперсидского, сохранился до раннего средневековья. 7. Бурушаски язык Язык бурушаски ( ...
... /диалект), скифский, согдийский, среднеперсидский, таджикский, таджриши (язык/диалект), талышский, татский, хорезмийский, хотаносакский, шугнано-рушанская группа языков, ягнобский, язгулямский и др. Они относятся к индоиранской ветви индоевропейских языков. Области распространения: Иран, Афганистан, Таджикистан, некоторые районы Ирака, Турции, Пакистана, Индии, Грузии, Российской Федерации. Общее ...
0 комментариев