Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Cpp_Страуструп.doc
Скачиваний:
16
Добавлен:
03.05.2015
Размер:
3.2 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 обычно

происходит намного быстрее, чем доступ к полю. Поля - это просто

удобная краткая форма задания логических операций для извлечения

или занесения информации в части слова.