Час життя – це проміжок часу існування об'єкта в процесі виконання програми. Він буває глобальним і локальним. Глобальний – коли об'єкт існує протягом усього часу виконання програми. Локальний – коли об'єкт існує на деякому проміжку, що включається до часу виконання програми.
Під областю дії об'єкта розумітимемо частину програми (коду програми), де можливим є використання імені об'єкта. Існують об'єкти, що мають глобальний час життя, але локальну область дії.
Під оголошенням функції розумітимемо конструкцію, у якій задається лише прототип функції та (необов'язково) специфікація класу пам'яті. Наприклад:
float s=5;
float f(float);
s=s+f(1);
У другому рядку лише оголошується функція f, тіло якої визначається в іншому місці програми (напр., нижче за текстом).
Під визначенням змінної розумітимемо конструкцію, обробка якої викликає виділення пам'яті. Наприклад:
int i=0;
Під оголошенням змінної розумітимемо конструкцію, яка є лише посиланням на визначення, зроблені в іншому місці програми (зазвичай в іншому файлі). Наприклад:
|
|
int i;
i=4;
//...
{
static int i=5;
}
Розглянемо рядок програми int i; Як його інтерпретувати з погляду оголошення чи визначення змінної i? Це може бути як оголошення, так і визначення. Якщо в програмі більше не зустрічається оголошення чи визначення змінної i, то це буде визначенням. Воно супроводжується виділенням пам'яті та ініціалізацією нулем, якщо цей рядок коду знаходиться на зовнішньому рівні. Якщо в іншому місці програми знаходиться визначення змінної i, то вказана конструкція є оголошенням:
Файл1 файл2
int i; int i=5;
…
Змінна вважається оголошеною на зовнішньому рівні, якщо вона знаходиться в тексті програми за межами функції. Якщо змінна описана всередині функції, то вважається, що вона визначена на внутрішньому рівні. Функція може бути визначена лише на зовнішньому рівні, але оголошена й на внутрішньому:
Main()
{ …
{
float f(int,int);
i++;
…};
};
Змінна, визначена на зовнішньому рівні, має глобальний час життя та область дії від точки визначення до кінця вихідного файла. Вище від точки визначення у файлі змінна недоступна:
…..
Void f(void)
{
i++;
}
int i=5;
Main()
{
i++;
}
…
У функції f змінна і недоступна. Щоб вона була доступною, необхідно розширити область дії змінної шляхом її оголошення перед функцією f: int i;
Змінна, оголошена на внутрішньому рівні, має локальний час життя та область дії від точки визначення до кінця блоку. За межами блоку, де вона не визначена, змінна недоступна.
Оголошення функції можливе й на внутрішньому рівні. Тоді область дії функції поширюється від точки визначення до кінця файла.
|
|
Класи пам'яті
Існує чотири специфікації класів пам'яті:
a register;
a auto;
a static;
a extern.
Специфікатори класу пам'яті можуть впливати на час життя та область дії програмних об'єктів. Специфікатор класу пам'яті register дозволяє розміщувати відповідну змінну (типу int) у регістрах мікропроцесора. Якщо місця там немає, то відповідна специфікація ігнорується і змінна вважається автоматичною, тобто має клас пам'яті auto. Клас пам'яті auto може бути випущеним. Будь-яка змінна вважається автоматичною за умовчанням, локальна змінна записується в стек. Специфікатор класу пам'яті static, що застосовується до зовнішнього об'єкта – змінної чи функції, – обмежує область дії лише вихідним файлом. Відповідний специфікатор може застосовуватись і до внутрішніх об’єктів. Це дає можливість вплинути на час життя відповідної змінної – він стає глобальним. Наприклад:
{
static int i;
…
}
Статистичні змінні записуються у сегмент даних.
Специфікатор класу пам'яті extern указує компілятору на те, що даний об'єкт є лише посиланням на визначення в іншому місці програми:
Файл1 файл2
extern int i; int i=5;
Зауважимо, що при визначенні змінної допускається її ініціалізація:
TYPE x=вираз;або
TYPE x; /*опис*/x=вираз; /*обрахування початкового значення*/Розглянемо фрагмент програми:
#include <stdio.h> extern double sqrt(); /*квадратний корінь*/ double x=1.17; double s12=sqrt(12.0); /*#1*/ double y=x*2.0; /*#2*/ FILE *fp=fopen("out.out","w"); /*#3*/ main(){ double ss=sqrt(25.0)+x; /*#4*/... }Рядки з мітками #1, #2 і #3 помилкові, адже при ініціалізації статичних даних (а s12, y і fp такими і є, оскільки описані поза тілом деякої функції) вираз має складатися тільки з констант, оскільки він обраховується компілятором. Тому ні використання значень змінних, ні виклики функцій у даному випадку не допустимі (але можна брати адресу змінних).
У рядку #4 ми ініціалізуємо автоматичну змінну ss. Тому вираз для ініціалізації обраховується вже не компілятором, а під час виконання програми, що дає нам право використовувати змінні, виклики функцій і т. п., тобто вирази мови С, без обмежень.
Інформацію про залежність часу життя та області дії від класу пам'яті й рівня оголошення чи визначення наведено в табл. 6.1.
Таблиця 6.1
Рівень | Об'єкт | СПКП | Час життя | Область дії |
Зовнішній | визначення змінної | Static | глобальний | від точки визначення до кінця файла |
оголошення змінної | Extern | глобальний | від точки визначення до кінця файла | |
оголошення чи визначення функції | Externчи Static | глобальний | від точки визначення до кінця файла | |
Внутрішній | оголошення змінної | Extern | глобальний | блок |
визначення змінної | Static | глобальний | блок | |
визначення змінної | Auto чи Register | локальний | блок | |
оголошення функції | Extern чи Static | глобальний | залишок вихідного файла |