Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 16 17 18 [ 19 ] 20 21 22 ... 120


most significant=04 0000, 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 обычно происходит намного быстрее, чем доступ к полю. Поля - это просто удобная краткая форма задания логических операций для извлечения или занесения информации в части слова.

2.6.2. Объединения

Рассмотрим таблицу имен, в которой каждый элемент содержит имя задаваться либо строкой, либо целым числом:

struct entry { char* name; char type;

char* string value; используется если type

int int value; используется если type

void print entry(entry* p)

switch(p->type) { case s:

cout << p->string value;

break; case i:

cout << p->int value;

break; default:

cerr << type corrupted\n ;

break;

и его значение. Значение может

Поскольку переменные string value и int value никогда не могут использоваться одновременно, очевидно, что часть памяти пропадает впустую. Это можно легко исправить, описав обе переменные как члены объединения, например, так:

struct entry { char* name; char type; union {

char* string value;

int int value;

используется если type == s используется если type == i

Теперь гарантируется, что при выделении памяти для entry члены string value и int value будут размещаться с одного адреса, и при этом не нужно менять все части программы, работающие с entry. Из этого следует, что все члены объединения вместе занимают такой же объем памяти, какой занимает наибольший член объединения.

Надежный способ работы с объединением заключается в том, чтобы выбирать значение с помощью того же самого члена, который его записывал. Однако, в больших программах трудно гарантировать, что объединение используется только таким способом, а в результате использования не того члена обЪединения могут возникать трудно обнаруживаемые ошибки. Но можно встроить объединение в такую структуру, которая обеспечит правильную связь между значением поля типа и текущим типом члена объединения ($$5.4.6).

Иногда объединения используют для псевдо-преобразований типа (в основном на это идут программисты, привыкшие к языкам, в которых нет средств преобразования типов, и в результате приходится обманывать транслятор). Приведем пример такого преобразования int в int* на машине VAX, которое достигается простым совпадением разрядов:

struct fudge { union {



int i; int* p;

fudge a; a.i = 4095;

int* p = a.p; некорректное использование

В действительности это вовсе не преобразование типа, т.к. на одних машинах int и int* занимают разный объем памяти, а на других целое не может размещаться по адресу, задаваемому нечетным числом. Такое использование объединений не является переносимым, тогда как существует переносимый способ задания явного преобразования типа ($$3.2.5).

Иногда объединения используют специально, чтобы избежать преобразования типов. Например, можно использовать fudge, чтобы узнать, как представляется указатель 0:

fudge.p = 0;

int i = fudge.i; i необязательно должно быть 0

Объединению можно дать имя, то есть можно сделать его полноправным типом. Например, fudge можно описать так:

union fudge { int i; int* p;

и использовать (некорректно) точно так же, как и раньше. Вместе с тем, поименованные объединения можно использовать и вполне корректным и оправданным способом (см. $$5.4.6).

2.7 Упражнения

1. Запустить программу Hello, world (см. $$1.3.1).

2. (*1) Для каждого описания из $$2.1 сделать следующее: если описание не является определением, то написать соответствующее определение; если же описание является определением, написать для него описание, которое не являлось бы одновременно и определением.

3. (*1) Напишите описания следующих объектов: указателя на символ; массива из 10 целых; ссглки на массив из 10 целых; указателя на массив символьных строк; указателя на указатель на символ; целого-константы; указателя на целое-константу; константного указателя на целое. Описания снабдить инициализацией.

4. (*1.5) Напишите программу, которая печатает размеры основных типов и типа указателя. Используйте операцию sizeof.

5. (*1.5) Напишите программу, которая печатает буквы от a до z и цифры от 0 до 9 и их целые значения. Проделайте то же самое для других видимых символов. Проделайте это, используя шестнадцатеричную запись.

6. (*1) Напечатайте последовательность разрядов представления указателя 0 на вашей машине. Подсказка: см.$$2.6.2.

7. (*1.5) Напишите функцию, печатающую порядок и мантиссу параметра типа double.

8. (*2) Каковы на используемой вами машине наибольшие и наименьшие значения следующих типов: char, short,int,long, float, double, long double, unsigned, char*, int* и void*? Есть ли какие-то особые ограничения на эти значения? Например, может ли int* быть нечетным целым? Как выравниваются в памяти объекты этих типов? Например, может ли целое иметь нечетный адрес?

9. (*1) Какова максимальная длина локального имени, которое можно использовать в вашей реализации С++ ? Какова максимальная длина внешнего имени? Есть ли какие-нибудь ограничения на символы, которые можно использовать в имени?

10. (*1) Напишите функцию, которая меняет местами значения двух целых. В качестве типа параметров используйте int*. Напишите другую функцию с тем же назначением, используя в качестве типа параметров int&.



1 ... 16 17 18 [ 19 ] 20 21 22 ... 120

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика