Основные типы данных
-
Тип данных
Размер, бит
Диапазон значений
unsigned char
8
0 ... 255
char
8
-128 ... 127
enum
16
-32768 ... 32767
unsigned int
16
0 ... 65535
short int (short)
16
-32768 ... 32767
unsigned short
16
0 ... 65535
int
16
-32768 ... 32767
unsigned long
32
0 ... 4294967295
long
32
-2147483648 ... 2147483647
float
32
3.4Е-38 ... 3.4Е+38
double
64
1.7E-308 ... 1.7E+308
long double
80
3.4E-4932 ... 1.1E+4932
Предельные значения целочисленных переменных совпадают с предельными значениями соответствующих констант (см. табл. 1). Табл. 3 содержит и предельные значения для тех типов, которые не включены в· табл. 1.
Инициализация переменных. В соответствии с синтаксисом языка переменные автоматической памяти после определения по умолчанию имеют неопределенные значения. Надеяться на то, что они равны, например, 0, нельзя. Однако переменным можно присваивать начальные значения, явно указывая их в определениях:
тип имя _ переменной=начальное _значение;
Этот прием назван инициализацией. В отличие от присваивания, которое осуществляется в процессе выполнения программы, инициализация выполняется при выделении для переменной участка памяти. Примеры определений с инициализацией:
float рi=3.1415, сс=1.2З;
unsigned int year=1997;
Именованные константы. В языке Си, кроме переменных, могут быть определены константы, имеющие фиксированные названия (имена). В качестве имен констант используются произвольно выбираемые программистом идентификаторы, не совпадающие с ключевыми словами и с другими именами объектов. Традиционно принято, что для обозначений констант выбирают идентификаторы из больших букв латинского алфавита и символов подчеркивания. Такое соглашение позволяет при просмотре большого текста программы на языке Си легко отличать имена переменных от названий констант.
Первая возможность определения именованных констант была проиллюстрирована в § 1.2. Это перечисляемые константы, вводимые с использованием служебного слова enum.
Вторую возможность вводить именованные константы обеспечивают определения такого вида:
const тип имя_константы=значение_константы;
где const - квалификатор типа, указывающий, что определяемый объект имеет постоянное значение, т.е. доступен только для чтения;
тип - один из типов объектов;
имя_константы идентификатор;
значение _константы должно соответствовать ее типу.
Примеры:
const double Е=2.718282;
const long М=99999999;
const F=765;
В последнем определении тип константы не указан, по умолчанию ей приписывается тип int.
Третью возможность вводить именованные константы обеспечивает препроцессорная директива
#define имя_константы значение_константы
Обратите внимание на отсутствие символа "точка с запятой" в конце директивы.
Отличие определения именованной константы
const double Е=2.718282;
от определения препроцессорной константы с таким же значением
#define EULER 2.718282
состоит внешне в том, что в определении константы Е явно задается ее тип, а при препроцессорном определении константы EULER ее тип определяется "внешним видом" значения константы. Например, следующее определение
#define NEXT 'z'
вводит обозначение NEXT ДЛЯ символьной константы 'z'. Это соответствует такому определению:
const char NEXT = 'z';
Однако различия между обычной именованной константой и препроцессорной константой, вводимой директивой #define, гораздо глубже и принципиальнее. До начала компиляции текст программы на языке Си обрабатывается специальным компонентом транслятора - препроцессором. Если в тексте встречается директива
#define EULER 2.718282
а ниже ее в тексте используется имя константы EULER, например, в таком виде:
double mix = EULER;
d = alfa*EULER;
то препроцессор заменит каждое обозначение EULER на ее значение и сформирует такой текст:
double mix = 2.718282;
d = alfa*2.718282;
Далее текст от препроцессора поступает к компилятору, который уже "и не вспомнит" о существовании имени EULER, использованного в препроцессорной директиве #define. Константы, определяемые на препроцессорном уровне с помощью директивы #define, очень часто используются для задания размеров массивов.
Итак, основное отличие констант, определяемых препроцессорными директивами #define, состоит в том, что эти константы вводятся в текст программы до этапа ее компиляции. Специальный компонент транслятора - препроцессор обрабатывает исходный текст программы, подготовленный программистом, и делает в этом тексте замены и подстановки. Пусть в исходном тексте встречается директива:
#define ZERO 0.0
Это означает, что каждое последующее использование в тексте программы имени ZERO будет заменяться на 0.0.
Рисунок 1.1 иллюстрирует некоторые принципы работы препроцессора. Его основное отличие от других компонентов транслятора - обработка программы выполняется только на уровне ее текста. На входе препроцессора - текст с препроцессорными директивами, на выходе препроцессора - модифицированный текст без препроцессорных директив. Этот выходной модифицированный текст изменен по сравнению с входным текстом за счет выполнения препроцессорных директив, но сами препроцессорные директивы в выходном тексте отсутствуют. Полностью все препроцессорные директивы будут рассмотрены позже. В связи с именованными константами здесь рассматривается только одна из возможностей директивы #define простая подстановка.
Текст до препроцессора (исходный текст программы):
-
#define PI 3.141593
#define ZERO 0.0
…….
if (r>ZERO)/* Сравнение с константой ZERO * / /* Длина окружности радиуса r:*/
D=2*PI*r;
……..