Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_СП_2004_1_00.doc
Скачиваний:
69
Добавлен:
04.11.2018
Размер:
882.69 Кб
Скачать

2. Классы памяти

Одно из достоинств языка Си состоит в том, что он позволяет управлять ключевыми механизмами программы. Понятие классов памяти является примером такого управления. Они дают возможность определить, с какими функциями связаны какие переменные и как долго тот или иной объект программы сохраняется в памяти ЭВМ. Другими словами, назначая класс памяти для какого-либо элемента, программист определяет тем самым время существования этого элемента (глобальное или локальное). Область же видимости элемента данных характеризуется уровнем (внешним или внутренним), на котором он определен в программе. Несмотря на то, что в языке Си существуют лишь два принципиально различных механизма представления объектов программы - глобальный и локальный, принято, тем не менее, выделять четыре основных класса памяти, используя для их назначения в программе следующие ключевые слова:

auto extern static register

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

2.1. Автоматические переменные (класс памяти auto)

Объекты программы, принадлежащие классу памяти auto и именуемые обычно автоматическими переменными, имеют локальное время существования и область их видимости ограничена тем блоком, в котором они определены. Память для их представления выделяется динамически из программного стека в момент входа в этот блок и возвращается назад системе по достижении его конца. По умолчанию все переменные, описанные на внутреннем уровне (т. е. в теле функции), являются автоматическими. Однако это можно явно подчеркнуть, используя ключевое слово auto:

main()

{ auto int alpha, beta;

auto char line[81];

.......................

.......................

.......................

}

Поскольку любые переменные, описанные на внешнем уровне, должны иметь глобальное время существования и размещаются поэтому в статической памяти, использование описателя auto вне какого-либо блока является недопустимым и приводит к ошибке. По этой же причине не разрешается назначать класс памяти auto для функций, ибо их определения не могут быть помещены в тело программного блока. Инициализация простых автоматических переменных задается обычным образом (см. Лекцию 3, $ 3) и выполняется при каждом входе в соответствующий блок. В случае же отсутствия инициализирующего выражения в инструкции описания данных, значение любой такой переменной считается неопределенным. Инициализация любых агрегатированных данных (например, массивов), имеющих класс памяти auto, не поддерживается компилятором языка Си.

Замечание. Поскольку память под представление автоматических переменных выделяется из программного стека, при построении готовой к выполнению программы из объектных модулей необходимо задать размер стека таким, чтобы его хватило для размещения всех этих переменных в самой большой по объему данных программной компоненте.

2.2. Внешние объекты программы (класс памяти extern)

Внешними объектами программы принято называть переменные, определенные вне какой-либо функции, и сами эти функции, поскольку определение одной функции в теле другой не является допустимым. По умолчанию всякая внешняя переменная имеет глобальное время существования, а область ее видимости лежит между точкой описания в программе и концом текущего файла. Это означает, что любая функция, определенная после описания некоторой внешней переменной в пределах одного файла, может использовать эту переменную без каких-либо дополнительных объявлений. Если же возникает необходимость в использовании внешних переменных до их фактического определения в текущем или даже другом файле, их нужно явным образом описать как имеющие класс памяти extern в теле соответствующей функции. В следующем примере:

main()

{ extern int number; /* Описание внешней переменной */

...................

...................

...................

}

.....................

.....................

.....................

int number = 17; /* Определение внешней переменной */

.....................

.....................

.....................

переменная number используется функцией main() раньше, чем она определена в программе. Ее начальное значение в этой функции равно 17. С точки зрения рассмотренных понятий времени существования и видимости объектов программы, важно различать описания внешних переменных и их определения. Так, описания начинаются с ключевого слова extern и могут встречаться многократно на внешнем и внутреннем уровнях, задавая тем самым область видимости соответствующих переменных. Наоборот, отсутствие описателя extern при определении внешней переменной требует от системы фактического выделения памяти для ее размещения. Любая такая переменная может быть определена лишь один раз во всей совокупности файлов, образующих исходную программу. Инициализация внешних переменных и структур данных всегда допустима в инструкциях, определяющих эти объекты в программе, и выполняется один раз перед началом ее работы. Те элементы данных, для которых инициализирующие выражения явным образом не заданы, по умолчанию инициализируются нулем. Инструкции описания внешних переменных, начинающиеся с ключевого слова extern, не могут содержать инициализирующих выражений. Использование внешний переменных в программах на языке Си часто оказывается полезным в тех случаях, когда возникает необходимость в передаче больших объемов информации между отдельными функциями или когда множество функций используют одни и те же данные. В обоих этих случаях использование аппарата формальных/фактических параметров приводит к излишней громоздкости и плохой структурированности программы. Однако неоправданное расширение области видимости большого количества переменных путем их обобществления может снизить надежность программного обеспечения.

2.3. Статические переменные и функции (класс памяти static)

Описатель класса памяти static может использоваться в инструкциях определения данных как на внешнем, так и на внутреннем уровнях. Внешние статические переменные имеют глобальное время существования, однако в отличие от обычных внешних переменных, доступ к ним ограничен частью текущего файла, лежащей после определения любой

такой переменной в программе. Ссылка на статические переменные из другого файла или их использование до фактического определения в текущем файле не допустимо. Таким образом, описатель static позволяет сузить область видимости внешней переменной. Внутренние статические переменные, как и переменные класса auto, имеют локальную видимость в пределах текущей функции (или блока), однако они сохраняются в памяти ЭВМ на протяжении всего времени работы программы. Это позволяет создавать об'екты с глобальным временем существования, ограничивая их видимость в программе. Так, например, переменная count, определенная в теле функции calc:

main()

{ ..................

..................

..................

}

calc()

{ static int count;

..................

..................

..................

}

может быть использована только в пределах этой функции, хотя она и сохраняет свое значение после завершения работы последней. Класс памяти static можно также назначать и при определении функций, ограничивая тем самым возможность доступа к ним пределами одного файла. Это позволяет иметь в разных файлах функции с одинаковыми именами, не опасаясь возникновения конфликтной ситуации. Инициализация статических переменных и структур данных допустима как на внешнем, так и на внутреннем уровнях, и выполняется по тем же правилам, что и для обычных внешних переменных.

2.4. Регистровые переменные (класс памяти register)

Регистровые переменные с точки зрения видимости, времени существования и возможностей инициализации полностью равносильны автоматическим переменным. Однако они сохраняются не в оперативной памяти машины, а на рабочих регистрах центрального процессора, что повышает эффективность выполнения программы. Если возможность такого хранения отсутствует (скажем, по причине занятости этих регистров), они становятся обычными автоматическими переменными. Этот класс памяти может назначаться только лишь для внутренних переменных и формальных параметров функций при помощи описателя register. Например:

func(p, q)

register int p, q;

{ register char sym;

...................

...................

...................

}

Операция получения адреса для регистровых переменных не допустима. На многих типах ЭВМ этот класс памяти не может быть назначен переменным типа float.