Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КРАТКИЙ ОБЗОР С.doc
Скачиваний:
1
Добавлен:
26.10.2018
Размер:
2.11 Mб
Скачать

2.5.1. Перечисления

Есть способ связывания имен с целыми константами, который часто более удобен, чем описание с const. Например:       enum { ASM, AUTO, BREAK }; Здесь определены три целых константы, которые называются элементами перечисления, и им присвоены значения. Поскольку по умолчанию значения элементов перечисления начинаются с 0 и идут в возрастающем порядке, то приведенное перечисление эквивалентно определениям:       const ASM = 0;       const AUTO = 1;       const BREAK = 2; Перечисление может иметь имя, например:       enum keyword { ASM, AUTO, BREAK }; Имя перечисления становится новым типом. С помощью стандартных преобразований тип перечисления может неявно приводиться к типу int. Обратное преобразование (из типа int в перечисление) должно быть задано явно. Например:       void f()       {       keyword k = ASM;       int i = ASM;       k = i // ошибка       k = keyword(i);       i = k;       k = 4; // ошибка       } Последнее преобразование поясняет, почему нет неявного преобразования из int в перечисление: большинство значений типа int не имеет представления в данном перечислении. Описав переменную с типом keyword вместо очевидного int, мы дали как пользователю, так и транслятору определенную информацию о том, как будет использоваться эта переменная. Например, для следующего оператора       keyword key;       switch (key) {       case ASM:       // выполнить что-либо       break;       case BREAK:       // выполнить что-либо       break;       } транслятор может выдать предупреждение, поскольку из трех возможных значений типа keyword используются только два.       Значения элементов перечисления можно задавать и явно. Например:       enum int16 {       sign=0100000,       most_significant=040000,       least_significant=1       }; Задаваемые значения необязательно должны быть различными, положительными и идти в возрастающем порядке.

2.6. Экономия памяти

В процессе создания нетривиальной программы рано или поздно наступает момент, когда требуется больше памяти, чем можно выделить или запросить. Есть два способа выжать еще некоторое количество памяти: [1] паковать в байты переменные с малыми значениями; [2] использовать одну и ту же память для хранения разных объектов       в разное время. Первый способ реализуется с помощью полей, а второй - с помощью объединений. И те, и другие описываются ниже. Поскольку назначение этих конструкций связано в основном с оптимизацией программы, и поскольку, как правило, они непереносимы, программисту следует хорошенько подумать, прежде чем использовать их. Часто лучше изменить алгоритм работы с данными, например, больше использовать динамически выделяемую память, чем заранее отведенную статическую память.

2.6.1 Поля

Кажется расточительным использовать для признака, принимающего только два значения ( например: да, нет) тип char, но объект типа char является в С++ наименьшим объектом, который может независимо размещаться в памяти. Однако, есть возможность собрать переменные с малым диапазоном значений воедино, определив их как поля структуры. Член структуры является полем, если в его определении после имени указано число разрядов, которое он должен занимать. Допустимы безымянные поля. Они не влияют на работу с поименованными полями, но могут улучшить размещение полей в памяти для конкретной машины:       struct sreg {       unsigned enable : 1;       unsigned page : 3;       unsigned : 1; // не используется       unsigned mode : 2;       unsigned : 4; // не используется       unsigned access : 1;       unsigned length : 1;       unsigned non_resident : 1;       }; Приведенная структура описывает разряды нулевого регистра состояния DEC PDP11/45 (предполагается, что поля в слове размещаются слева направо). Этот пример показывает также другое возможное применение полей: давать имена тем частям объекта, размещение которых определено извне. Поле должно иметь целый тип ($$R.3.6.1 и $$R.9.6), и оно используется аналогично другим объектам целого типа. Но есть исключение: нельзя брать адрес поля. В ядре операционной системы или в отладчике тип sreg мог бы использоваться следующим образом:       sreg* sr0 = (sreg*)0777572;       //...       if (sr0->access) { // нарушение прав доступа       // разобраться в ситуации       sr0->access = 0;       }       Тем не менее,       применяя поля для упаковки нескольких переменных в один байт, мы       необязательно сэкономим память. Экономится память для данных, но       на большинстве машин одновременно возрастает объем команд,       нужных для работы с упакованными данными.       Известны даже такие программы, которые значительно сокращались в объеме,       если двоичные переменные, задаваемые полями, преобразовывались в       переменные типа char! Кроме того, доступ к char или int обычно       происходит намного быстрее, чем доступ к полю. Поля - это просто       удобная краткая форма задания логических операций для извлечения       или занесения информации в части слова.