C Урок 23. Время жизни в C. Часть 1



В уроке 21 мы познакомились с областью видимости данных. Также у различных типов данных, а также не только у данных существует и время жизни. То есть наступает такой момент, когда какие-то данные (переменные, экземпляры структур, массивы) перестают существовать. Если мы после этого момента попытаемся их использовать, то ситуация будет такая же, как если бы их вообще никогда не существовало.

Время жизни данных неразрывно связано с классами памяти в C. Классы памяти, а также и данные, им принадлежащие, бывают статические, автоматические, динамические, внешние и регистровые.

Данные, принадлежащие к статическому классу памяти предваряются спецификатором static, например

 

static int n;

 

Что же даёт нам данный спецификатор?

Ответ — смотря где.

Для этого мы должны ещё познакомиться с термином блок.

Блок в программе — это участок кода между открывающей фигурной скобкой и закрывающей, причём закрывающей именно тело этого оператора, конструкции или функции. То есть, в сущности, блок и есть тело оператора, конструкции или функции

 

 

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

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

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

 

int n;

и так

auto int n;

 

Переменные данного класса живут также до конца тела блока, но выходе из блока их состояние (значение) не сохраняется. Всё это достигается тем, что память, выделяемая для переменных типа static, располагается в статической памяти, в которой в отличие от динамической памяти (heap) память для статических переменных выделяется при запуске программы и не меняется, а также не освобождается до окончания работы приложения, а память для автоматических данных выделяется в стеке, указатель на вершину которого, как известно, сохраняется перед вызовом функции и восстанавливается после выхода из неё.

 

 

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

 

register int n;

 

Глобавльный или внешний класс памяти относится к переменным или другим типам данных, предваряемых спецификатором extern. Мы с таким классом уже работали в уроке по области видимости и знаем, как он действует.

Также существует динамический класс памяти, но в рамках данного урока нами он также рассмотрен не будет, так как к времени жизни он по моему мнению мало относится. Скажу лишь, что это такая память, которую мы отдельно просим у операционной системы по мере надобности. Также после того, когда нам эта память будет не нужна, мы спокойно можем её освободить.

Теперь, когда мы уже достаточно узнали о времени жизни данных, то можно приступить уже и к проекту. Теперь он может полноправно считаться проектом, так как с прошлого урока мы уже работаем со средой программирования Eclipse и создавали его именно как проект.

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

Поэтому создадим папку для проекта MYPROG23 и скопируем в неё полностью всё из папки с проектом прошлого урока с именем MYPROG22. Перед этим желательно произвести очистку (clean) проекта прошлого урока. Я также буду стараться к статьям прикреплять уже очищенные проекты.

В папке с новым проектом MYPROG23 откроем файл .cproject и везде, где встретится сторока 'MYPROG22' заменим её на 'MYPROG23', практически заменив только последнюю цифру 2 на 3.

Сохраним изменённый файл и сделаем аналогичные изменения в файле .project. Там данная строка встретится только один раз.

Запустим Eclipse.

Теперь нам нужно открыть здесь данный проект. Делается это следующим образом.

В любом месте дерева проекта вызовем контекстное меню с помощью клика по правой кнопке мыши и выберем там пункт Import

 

 

В открывшемся диалоге выберем следующий пункт дерева и нажимаем Next

 

 

 

В следующем открывшемся диалоге нажимаем кнопку Browse

 

 

Откроется стандартный диалог выбора папки, в котором выберем папку с нашими проектами и нажимаем кнопку «Выбор папки»

 

 

Внизу появятся наши проекты. Оставим галку только на нужном нам проекте и нажмём кнопку Finish

 

 

Наш новый проект теперь присутствует в дереве проектов

 

 

Откроем Makefile и прежде, чем вносить в него изменения, давайте настроим среду так, чтобы шрифт в нём тоже не был маленьким. Для этого откроем пункт меню Window -> Preferences и в открывшемся диалоге в левой панели выберем соответствующий пункт, а в правой затем раскроем пункт Basic

 

 

В раскрывшемся списке выберем пункт Text Font и нажмём кнопку Edit

 

 

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

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

В Makefile, в котором шрифт у нас уже не мелкий, мы всего лишь в одном месте внесём изменения, также изменив имя выполняемого файла на myprog23

 

 

Вот мы и сделали проект из проекта прошлого урока. Нам не придётся заново создавать файлы всех модулей, делать настройки в свойствах проекта.

Проект наш теперь успешно соберётся

 

 

Только если мы попробуем проект запустить на выполнение, то у нас скорее всего соберётся и выполнится проект прошлого урока MYPROG22, поэтому в настройках в пункте Run/Debug Settings мы должны будем так же, как и в прошлом занятии, создать конфигурацию для запуска и отладки нашего приложения.

Теперь при попытке первый раз выполнить или отладить наш проект мы выберем именно эту конфигурацию

 

 

Наш проект теперь выполнится

 

 

Теперь можем смело приступить к работе с проектом, а то мы уже скорей всего забыли о том, что мы работаем сегодня с временем жизни данных.

 

В следующей части урока мы практически поработаем с переменными, принадлежащим к различным классам памяти.

 

 

Предыдущий урок Программирование на C Следующая часть

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

C Время жизни в C

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*