Язык Си - Уэйт, Прата, Мартин. M. уэит с. Прата д. Мартин
Скачать 4.69 Mb.
|
ДАННЫЕ: ТИПЫ ДАННЫХ Далее Содержание 32 Помимо различия между переменными и константами существует еще различие между типами данных. Некоторые данные в программе являются числами, некоторые - буквами, или, более обобщенно, символами. Компьютер должен иметь возможность идентифицировать и обрабатывать требуемым образом данные любого из этих типов. В языке Си предусмотрено использование нескольких основных типов данных. Если величина есть константа, то. компилятор обычно может распознать ее тип только по тому виду, в каком она присутствует в программе. Однако в случае переменной необходимо, чтобы ее тип был объявлен в операторе описания. Дополнительные детали, относящиеся к типам данных, мы будем сообщать вам по мере изложения. Рассмотрим основные типы данных, имеющиеся в языке Си. В стандарте языка Си используется семь ключевых слов, указывающих на различные типы данных. Приведем список этих ключевых слов: int long short unsigned char float double Первые четыре ключевых слова используются для представления целых, т. е. целых чисел без десятичной дробной части. Они могут появляться в программе по отдельности или в некоторых сочетаниях, как, например, unsigned short. Следующее слово char предназначено для указания на буквы и некоторые другие символы, такие, как #, $, % и &. Последние два ключевых слова используются для представления чисел с десятичной точкой. Типы, обозначаемые этими ключевыми словами, можно разделить на два класса по принципу размещения в памяти машины. Первые пять ключевых слов определяют "целые" типы данных, в то время как последние два - типы данных с "плавающей точкой". РИС. 3.1. Работа функций scanf( ) и printf( ). В этом месте у некоторых читателей могут появиться недоумен-ные вопросы: "Целые типы данных? Типы данных с плавающей теневой?" Не пугайтесь. Если эти термины кажутся вас непривычными или непонятными, мы дадим краткое объяснение их смысла. Те, кто не знаком с 33 терминами "биты", "байты" и "слова", могут, перед тем как двинуться дальше, прочесть приводимое ниже объяснение, отмеченное вертикальной голубой линией. Можно спросить: а нужно ли знать все эти детали? На самом деле необязательно. Пожалуй, не больше, чем вы должны знать о принципах работы двигателя внутреннего сгорания для того, чтобы управлять машиной. Но некоторое представление о том, что происходит в компьютере или двигателе, может иногда выручить вас. Кроме того, это может помочь вашему превращению в прекрасного "собеседника". Термины "бит", "байт" и "слово" обычно используются для описания как элементов данных, которые обрабатывает компьютер, так и элементов памяти. Здесь мы займемся рассмотрением второго смысла этих терминов. Наименьшая единица памяти называется бит. Она может принимать одно из ДВУХ значений: 0 или 1. (Иначе говоря, бит может находится в состояниях "включен" или "выключен"; эта фраза совершенно аналогична первому выска зыванию.) В один бит нельзя поместить достаточное количество информации но в машине содержится большое число битов; дело в том, что бит - основной "строительный блок", из которых создается память компьютера. Байт - более удобный элемент памяти. В большинстве машин байт состоит из 8 бит. Поскольку каждый бит можно установить либо в состояние 0, либо в состояние 1, всего в байтовом формате можно представить 256 (два в восьмой степени) различных комбинаций из нулей и единиц. Такие комбинации можно использовать, например, для представления целых чисел в диапазоне от 0 до 255 или для кодирования набора символов. Это можно получить при помощи "дво-ичного кода", в котором для представления чисел используются только нули и единицы. Обсуждение структуры двоичного кода мы поместили в приложение (вы вполне можете его не читать, если не захотите). При современном подходе к проектированию компьютеров слово является самым естественным элементом памяти. В 8-разрядных микрокомпьютерах, таких, как ЭВМ фирмы Sinklair иди первые модели машин фирмы Apple, слово занимает как раз 1 байт. Многие более новые персональные вычислительные системы, такие, как IBM PC и Lisa фирмы Apple, являются 16-разрядными. Это означает, что размер слова у них 16 бит, т. е. 2 байта. Большие компьютеры могут иметь 32-, 64-разрядные слова или даже более длинные. Совершенно очевидно, что чем длиннее слово, тем больше информации можно туда поместить. Обычно в компьютерах предусмотрена возможность объединять вместе два или более слов для того, чтобы помещать в память элементы данных большей длины, но этот процесс сильно замедляет работу компьютера. В наших примерах мы предполагаем, что длина слова равна 16 бит, если мы не оговорили противного. Для человека различие между целым числом и числом с плавающей точкой выражается в способе записи. Для компьютера различие выражается в способе занесения этих чисел в память. Давайте рассмотрим по очереди каждый из двух классов чисел. Целые числа Далее Содержание У целого числа никогда не бывает дробной части и, согласно правилам языка Си, десятичная точка в его записи всегда отсутствует. В качестве примера можно привести числа 2, -23 и 2456. Числа вида 3.14 и 2/3 не являются целыми. Представив целое число в двоичном виде, его нетрудно разместить в памяти машины. 34 РИС. 3.2. Двоичное представление числа 7 в памяти машины. Например, число 7 в двоичном виде выглядит как 111. Поэтому, чтобы поместить это число в 1-байт слово, необходимо первые 5 бит установить в 0, а последние 3 бит - в 1 (рис. 3.2). Числа с плавающей точкой Далее Содержание Числа с плавающей точкой более или менее соответствуют тому, что математики называют "вещественными числами". Они включают в себя числа, расположенные между целыми. Вот некоторые из них: 2.75, 3.16Е7, 7.00 и 2е-8. Очевидно, что любое число с плавающей точкой можно записать несколькими способами. Более полное обсуждение "Е-нотации" будет проведено дальше, а мы Только кратко поясним, что запись вида "3.16Е7" означает число, полученное в результате умножения 3.16 на 1,0 в седьмой степени, т. е. на 1 с семью нулями. Число 7 называется "порядком" (показателем степени при основании 10). Наиболее существенным моментом здесь является то, что способ кодирования, используемый для помещения в память числа с плавающей точкой, полностью отличается от аналогичной схемы для размещения целого числа. Формирование представления числа с плавающей точкой состоит в его разбиении на дробную часть и порядок; затем обе части раздельно помещаются в память. Поэтому число 7.00 из вышеприведенного списка нельзя поместить в память тем же способом, что и целое число 7, хотя оба имеют одно и то же значение. В десятичной записи (точно так же как и в двоичной) число "7.0" можно было бы записать в виде "0.7Е1"; тогда "0.7" будет дробной частью, а "1" - порядком. Для размещения чисел в памяти машины будут, конечно, использоваться двоичные числа и степени двойки вместо степеней десяти. Дополнительную информацию, относящуюся к этому вопросу, вы сможете найти в приложении Ж. Здесь же мы остановимся лишь на различиях, связанных с практическим использованием чисел этих двух типов. 1. Целые числа не имеют дробной части, в то время как числа с плавающей точкой могут представлять как целые, так и дробные числа. 2. Числа с плавающей точкой дают возможность представлять величины из более широкого диапазона, чем целые (см. табл. 3.1). 3. При некоторых арифметических операциях, например при вычитании одного большого числа из другого, использование чисел с плавающей точкой приводит к большей потере точности. 4. Операции над числами с плавающей точкой выполняются, как правило, медленнее, чем операции над целыми числами. Однако сейчас уже появились микропроцессоры, специально ориентированные на обработку чисел с плавающей точкой, и в них эти операции выполняются довольно быстро. РИС. 3.3. Десятичное представление числа p в формате с плавающей точкой. Возьмите некоторое число. Добавьте к нему 1, а затем вычтите из полученной суммы исходное число. Что у вас получится? У нас получилась 1. Но вычисления, производимые над числами с плавающей точкой, могут дать и совершенно неожиданный результат: 35 /*ошибка вычислений*/ main( ) { float a, b; b = 2.0е20 + 1.0; а = b - 2.0е20; printf(" %f \n", a); } Результат равен 0000000 Причина появления такого странного результата состоит в отсутствии доста точного числа разрядов для выполнения операций с требуемой точностью. Число 2.0е20 записывается как двойка с последующими двадцатью нулями, и, до бавляя к нему 1, мы пытаемся изменить 21-ю цифру Чтобы выполнить эту oпe рацию корректно, программа должна иметь возможность поместить в память число, состоящее из 21 цифры. Но число типа float (т е. с плавающей точкой) путем изменения порядка можно увеличить или уменьшить лишь на 6 или 7 цифр. Попытка вычисления оказалась неудачной. С другой стороны, если бы мы использовали, скажем, число 2.0е4 вместо 2.0е20, мы смогли бы получить правильный ответ, поскольку в этом случае мы пытались бы изменить 5-ю цифру, и точность представления чисел типа float оказалась бы вполне достаточной для этого. ТИПЫ ДАННЫХ В ЯЗЫКЕ СИ Далее Содержание Давайте теперь рассмотрим некоторые специфические особенности основных типов данных, используемых в языке Си. Для каждого типа мы покажем, как описать переменную, как представить константу и как лучше всего использовать данные этого типа. В некоторых компиляторах с языка Си не реализована обработка всех типов данных; поэтому вам необходимо свериться с руководством по языку Си, имеющимся в комплекте вашей машины, чтобы посмотреть, какие из типов доступны для использования. Типы int, short и long Далее Содержание В языке Си имеется несколько целых типов, поэтому у вас есть возможность вносить изменения в свою программу, чтобы она удовлетворяла требованиям конкретной машины или определенного задания. Если вы не хотите заботиться о таких деталях, то, вообще говоря, вы можете просто остановиться на типе int и не думать больше о других возможностях. Все данные типов int, short и long являются "числами со знаком", т. е. допустимыми значениями переменных этих типов могут быть только целые числа - положительные, отрицательные и нуль. Один бит используется для указания знака числа, поэтому максимальное число со знаком, которое можно представить в слове, меньше, чем максимальное число без знака. Например, в формате 16-битного слова можно представить любые целые числа без знака, из диапазона от 0 до 65535. Точно так же 16-битное слово можно использовать для представления целых чисел со знаком из диапазона от -32768 до +32767. 36 Заметим, что длины диапазонов в обоих случаях одинаковые. Язык Си предоставляет пользователям возможность выбора размера элемента памяти (одного из трех) для представления це лых чисел. Типу int обычно соответствует стандартная длина слова, принятая на используемой машине. При этом гарантируется, что размер элементов памяти, отводимых под данные типа short и long, будет соответственно не больше и не меньше длины элемента памяти, выделяемого типу int. В некоторых вычислительных системах один или оба этих типа реализованы точно так же, как int. Все зависит от того, какое представление лучше соответствует архитектуре конкретной ЭВМ. В табл. 3.1 для каждого компьютера из некоторого множества приведено число битов, используемое для представления данных различных типов, а также диапазоны отображаемых чисел. Описание данных целого типа Далее Содержание При описании данных необходимо ввести только тип, за которым должен следовать список имен переменных. Ниже приведены некоторые возможные примеры описаний: int erns; short stops; long johns; int hogs, cows, goats; В качестве разделителя между именами переменных необходимо использовать запятую; весь список должен оканчиваться символом "точка с запятой". Вы можете собрать в один оператор описания переменных с одним и тем же типом или, наоборот, разбить одно описание на несколько операторов. Например, описание int erns, hogs, cows, goats; будет давать тот же самый эффект, что и два отдельных описания типа int в предшествующем примере. При желании вы даже могли бы использовать четыре различных описания данных типа int - по одному для каждой переменной. Иногда вам могут встретиться сочетания ключевых слов, как, например, long int или short int. Эти комбинации являются просто более длинной записью ключевых слов long и short. 37 Целые константы Далее Содержание Согласно правилам языка Си, число без десятичной точки и без показателя степени рассматривается как целое. Поэтому 22 и -273 - целые константы. Но число 22.0 нецелое, потому что в его записи имеется десятичная точка, и число 22Е3 тоже нецелое, поскольку в записи использован порядок. Кроме того, указывая целое число, нельзя использовать запятые. Нужно записать 23456 вместо 23,456. Если вы хотите ввести некоторую константу типа long, то можете это сделать, указав признак L или l в конце числа. Использование прописной буквы L более предпочтительно, поскольку ее труднее спутать с цифрой 1. Примером такой константы служит число 212L. Очевидно, что само по себе число 212 не очень большое, но добавление признака L гарантирует, что в памяти для него будет отведено необходимое число байтов. Это может оказаться важным для достижения совместимости, если данное число должно использоваться вместе с другими переменными и константами типа long. Вполне возможно, что вам уже ничего больше не нужно знать про то, как записывают константы, но в языке Си имеются еще и два других способа. Первый: если целое начинается с цифры 0, оно интерпретируется как "восьмеричное" число. Восьмеричные числа - это числа, представляемые "по основанию восемь" (т. е. их запись состоит из комбинаций степеней числа восемь). Например, 020 - это удвоенная первая степень основания восемь, т. е. восьмеричный эквивалент числа 16. При отсутствии в первой позиции нуля это просто обыкновенное (десятичное) число 20. Второй: целое, начинающееся с символом 0х или 0Х интерпретируется как шестнадцатеричное число, т. е. число, записываемое по основанию 16. Поэтому запись 0х20 представляет собой удвоенную первую степень числа 16, или 32. Восьмеричные и шестнадцатеричные числа чрезвычайно популярны среди программистов. Поскольку 8 и 16 являются степенями числa 2, а 10 - нет, использование этих систем счисления при работе на машине является вполне естественным. Например, число 65536, которое часто возникает при программировании на 16-разрядных компьютерах, в шестнадцатеричной записи имеет вид 10000. Если вы захотите больше узнать о восьмеричных и шестнадцатеричных числах, вы сможете найти дополнительный материал в приложении Ж. Инициализация переменных целого типа Далее Содержание Константы часто применяются при "инициализации" перемен ных. Это означает присваивание переменной некоторого значения перед началом обработки. Ниже приводятся примеры использова ния инициализации: erns = 1024; stops = -3; johns = 12345678; Если захотите, вы можете инициализировать переменную в операторе описания. Например: int hogs = 23; int cows = 32, goats = 14; short dogs, cats = 92; Заметим, что в последней строке была инициализирована только переменная cats. При невнимательном чтении может создаться впечатление, что переменная dogs тоже 38 инициализирована значением 92, поэтому лучше избегать смешивания инициализируемых и неинициализируемых переменных в одном операторе описания. Рекомендации Далее Содержание Какие переменные целого типа со знаком лучше всего использо вать? Одной из целей введения в язык трех классов целых чисел, имеющих различные размеры, было предоставить возможность со гласования типа переменной с требованиями задачи. Например, если переменная типа int занимает одно слово, а переменная типа long - два, то тип long позволяет обрабатывать большие числа. Если в вашей задаче такие большие числа не используются, то незачем и вводить в программу переменную типа long, так как, если вместо числа, занимающего одно слово памяти, используется число, занимающее два слова, работа машины замедляется. Вообще говоря, необходимость введения данных типа long целиком зависит от вашей вычислительной системы, поскольку под данные типа int на одной машине может отводиться больше памяти, чем под данные типа long на другой. В конце мы еще раз хотим напомнить вам, что обычно вполне достаточно использовать переменную типа int. Что происходит, когда в процессе обработки данных появляется значение, лежашее вне того диапазона чисел, которому соответствует данный целый тип? Давайте присвоим некоторой переменной целого типа наибольшее возможное значение, выполним операцию сложения и посмотрим, что произойдет /* переполнение */ main( ) { int i = 32767, printf( %d %d %d\n , i, i+l, i+2), } Ниже приведен результат работы этой программы, выполненной на нашей вычислительной системе 3 Целая переменная i ведет себя здесь как одометр 2) в машине. Когда его показания достигают максимума, данная величина "сбрасывается", и все начинается сначала. Основное отличие состоит в том, что показания одометра растут, начиная с нуля, а значения нашей переменной типа int - с величины - 32768. Заметим, что при этом вам не сообщают, что переменная i превысила макси мальное значение Для регистрации подобных событий вы должны использовать свои программные средства. Описанный подход не вытекает непосредственно из правил языка Си, а является довольно распространенным способом реализации. |