Константы и константные переменные
Повторение
В Си существует всего лишь несколько базовых типов:
ü char - единичный байт, который может содержать один символ из допустимого символьного набора;
ü int - целое, обычно отображающее естественное представление целых в машине;
ü float - число с плавающей точкой одинарной точности;
ü double - число с плавающей точкой двойной точности.
Имеется также несколько квалификаторов, которые можно использовать вместе с указанными базовыми типами. Например, квалификаторы short (короткий) и long (длинный) применяются к целым: short int sh; long int counter; В таких объявлениях слово int можно опускать, что обычно и делается.
К основному типу можно применять прилагательное const. Это задаёт тип, имеющий те же свойства, что и основной, но значение переменных типа const не может меняться после инициализации. Например,
const float x = 2.54;
Прилагательное unsigned (беззнаковое) используется только для целых типов.
К любой комбинации основных типов могут применяться арифметические операции +, -, *, / и операции сравнения ==, !=, <, >, <=, >=.
Константы и константные переменные
Целая константа, например 1234, имеет тип int. Константа типа long завершается буквой l или L, например 123456789L: слишком большое целое, которое невозможно представить как int, будет представлено как long. Беззнаковые константы заканчиваются буквой u или U, а окончание ul или UL говорит о том, что тип константы - unsigned long. Константы с плавающей точкой имеют десятичную точку (123.4), или экспоненциальную часть (1е-2), или же и то, и другое. Если у них нет окончания, считается, что они принадлежат к типу double. Окончание f или F указывает на тип float, а l или L - на тип long double. Целое значение помимо десятичного может иметь восьмеричное или шестнадцатеричное представление. Если константа начинается с нуля, то она представлена в восьмеричном виде, если с 0x или с 0X, то - в шестнадцатеричном. Например, десятичное целое 31 можно записать как 037 или как 0X1F. Записи восьмеричной и шестнадцатеричной констант могут завершаться буквой L (для указания на тип long) и U (если нужно показать, что константа беззнаковая). Например, константа 0XFUL имеет значение 15 и тип unsigned long.
При описании переменной можно присвоить начальное значение. Например,
char i = ‘A’;
В дальнейшем, переменная i может принять другое значение.
Если переменная объявлена с ключевым словом const, значит, она не должна меняться. Рассмотрим простой пример с константной целой переменной.
const int j = 17; //Целая константа. Слово int можно пропустить.
j = 29; //Нельзя, значение j не должно меняться
const int i; //Нельзя, отсутствует начальное значение
Компилятор ищет ошибки не только фактические, но и потенциальные. Компилятор не разрешит использовать константную переменную в контексте, когда ее значение может измениться.
const J = 17;
int& j = J; /*Делается попытка определить переменную j значением по адресу константы J. Нельзя, потому что позднее j может измениться. Неважно, будете ли вы изменять величину, на которую ссылается j. Поскольку это возможно, компилятор предполагает, что вам захочется это сделать, и определяет ситуацию как ошибочную. Неконстантная переменная не может ссылаться на константную величину*/
В Си имеется еще один вид константы - константа перечисления. Перечисление - это список целых констант, как, например, в enum boolean {NO, YES}; Первое имя в enum имеет значение 0, следующее - 1 и т.д. (если для значений констант не было явных спецификаций). Если не все значения специфицированы, то они продолжают прогрессию, начиная от последнего специфицированного значения, как в следующих двух примерах:
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t', NEWLINE = '\n', VTAB = '\v', RETURN = '\r'};
enum months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}; /* FEB есть 2, MAR есть 3 и т.д. */
Имена в различных перечислениях должны отличаться друг от друга. Значения внутри одного перечисления могут совпадать. Средство enum обеспечивает удобный способ присвоить константам имена, причем в отличие от #define значения констант при этом способе могут генерироваться автоматически. Хотя разрешается объявлять переменные типа enum, однако компилятор не обязан контролировать, входят ли присваиваемые этим переменным значения в их тип. Но сама возможность такой проверки часто делает enum лучше, чем #define. Кроме того, отладчик получает возможность печатать значения переменных типа enum в символьном виде.
Макросы
Две следующие строки не эквивалентны:
const int I = 17;
#define I 17;
В первой строке определяется переменная, занимающая некоторую область памяти, а во второй - макрос. Управляющая строка вида
#define идентификатор последовательность-лексем
заставляет препроцессор заменить идентификатор последовательностью лексем (в тексте программы идентификатор I будет заменен числом 17).