Звичайна C-програма є визначенням функції main, яка для виконання необхідних дій викликає інші функції. Наведені вище приклади програм були одним початковим файлом, що містить всі необхідні для виконання програми функції. Зв’язок між функціями здійснювався за даними за допомогою передачі параметрів і повернення значень функцій. Але компілятор мови Сі дозволяє також розбити програму на декілька окремих частин (початкових файлів), відтранслювати кожну частину окремо, і потім об’єднати всі частини в один виконуваний файл за допомогою редактора зв’язків.

При такій структурі початкової програми функції, ті, що знаходяться в різних початкових файлах можуть використовувати глобальні зовнішні змінні. Всі функції в мові Сі за визначенням зовнішні і завжди доступні з будь-яких файлів. Наприклад, якщо програма складається з двох початкових файлів, як показано на рис.2., то функція main може викликати будь-яку з трьох функцій fun1, fun2, fun3, а кожна з цих функцій може викликати будь-яку іншу.

file1.с file2.с

main()
{ ...
}
fun1()
{ ...
}

fun2()
{ ...
}
fun3()
{ ...
}

Рис.2. Приклад програми з двох файлів

Для того, щоб визначувана функція могла виконувати які або дії, вона повинна використовувати змінні. У мові Сі всі змінні повинні бути оголошені до їх використання. Оголошення встановлюють відповідність імені і атрибутів змінної, функції або типу. Визначення змінної викликає виділення пам’яті для зберігання її значення. Клас пам’яті, що виділяється, визначається специфікатором класу пам’яті, і визначає час життя і область видимості змінної, пов’язані з поняттям блоку програми.

У мові Сі блоком вважається послідовність оголошень, визначень і операторів, вкладена у фігурні дужки. Існують два види блоків - складовий оператор і визначення функції, що складається з складового оператора, що є тілом функції, і передування тілу заголовка функції (у який входять ім’я функції, типи значення, що повертається, і формальних параметрів). Блоки можуть включати складових операторів, але не визначення функцій. Внутрішній блок називається вкладеним, а зовнішній блок - охоплюючим.

Час життя - це інтервал часу виконання програми, протягом якого програмний об’єкт (змінна або функція) існує. Час життя змінної може бути локальним або глобальним. Змінна з глобальним часом життя має розподілену для неї пам’ять і певне значення протягом всього часу виконання програми, починаючи з моменту виконання оголошення цієї змінної. Змінна з локальним часом життя має розподілену для нього пам’ять і певне значення тільки під час виконання блоку, в якому ця змінна визначена або оголошена. При кожному вході в блок для локальної змінної розподіляється нова пам’ять, яка звільняється при виході з блоку.

Всі функції в Сі мають глобальний час життя і існують протягом всього часу виконання програми.

Область видимості - це частина тексту програми, в якій може бути використаний даний об’єкт. Об’єкт вважається видимим в блоці або в початковому файлі, якщо в цьому блоці або файлі відомі ім’я і тип об’єкту. Об’єкт може бути видимим в межах блоку, початкового файлу або у всіх початкових файлах, створюючих програму. Це залежить від того, на якому рівні оголошений об’єкт: на внутрішньому, тобто усередині деякого блоку, або на зовнішньому, тобто поза всіма блоками.

Якщо об’єкт оголошений усередині блоку, то він видний в цьому блоці, і у всіх внутрішніх блоках. Якщо об’єкт оголошений на зовнішньому рівні, то він бачимо від точки його оголошення до кінця даного початкового файлу.

Об’єкт може бути зроблений глобально видимим за допомогою відповідних оголошень у всіх початкових файлах, створюючих програму.

Специфікатор класу пам’яті в оголошенні змінної може бути auto, register, static або extern. Якщо клас пам’яті не вказаний, то він визначається за умовчанням з контексту оголошення.

Об’єкти класів auto і register мають локальний час життя. Специфікатори static і extern визначають об’єкти з глобальним часом життя.

При оголошенні змінної на внутрішньому рівні може бути використаний будь-який з чотирьох специфікаторів класу пам’яті, а якщо він не вказаний, то мається на увазі клас пам’яті auto.

Змінна з класом пам’яті auto має локальний час життя і видно тільки в блоці, в якому оголошена. Пам’ять для такої змінної виділяється при вході в блок і звільняється при виході з блоку. При повторному вході в блок цієї змінної може бути виділений інша ділянка пам’яті.

Змінна з класом пам’яті auto автоматично не ініціалізується. Вона повинна бути проініциалізована явно при оголошенні шляхом присвоєння їй початкового значення. Значення неініціалізованої змінної на клас пам’яті auto зважає невизначеним.

Специфікатор класу пам’яті register наказує компілятору розподілити пам’ять для змінної в регістрі, якщо це представляється можливим. Використання регістрової пам’яті звичайно приводить до скорочення часу доступу до змінної. Змінна, оголошена з класом пам’яті register, має ту ж область видимості, що і змінна auto. Число регістрів, які можна використовувати для значень змінних, обмежене можливостями комп’ютера, і в тому випадку, якщо компілятор не має у розпорядженні вільних регістрів, то змінній виділяється пам’ять як для класу auto. Клас пам’яті register може бути вказаний тільки для змінних з типом int або покажчиків з розміром, рівним розміру int.

Змінні, оголошені на внутрішньому рівні із специфікатором класу пам’яті static, забезпечую можливість зберегти значення змінної при виході з блоку і використати його при повторному вході в блок. Така змінна має глобальний час життя і область видимості всередині блоку, в якому вона оголошена. На відміну від змінних з класом auto, пам’ять для яких виділяється в стеку, для змінних з класом static пам’ять виділяється в сегменті даних, і тому їх значення зберігається при виході з блоку.

Приклад:

 1/* оголошення змінної i на внутрішньому рівні
 2   з класом пам'яті static.          */
 3
 4/*  початковий файл file1.c    */
 5
 6main()
 7{ ...
 8
 9}
10
11fun1()
12{ static int i=0; ...
13
14}
15
16/* початковий файл  file2.c    */
17
18fun2()
19{ static int i=0; ...
20
21}
22
23fun3()
24{ static int i=0; ...
25
26}

У наведеному прикладі оголошені три різні змінні з класом пам’яті static, що мають однакові імена i. Кожна з цих змінних має глобальний час життя, але видима тільки в тому блоці (функції), в якій вона оголошена. Ці змінні можна використовувати для підрахунку числа звернень до кожної з трьох функцій.

Змінні класу пам’яті static можуть ініціалізувати константним виразом. Якщо явної ініціалізації немає, то такою змінною привласнюється нульове значення. При ініціалізації константним адресним виразом можна використовувати адреси будь-яких зовнішніх об’єктів, окрім адрес об’єктів з класом пам’яті auto, оскільки адреса останніх не є константою і змінюється при кожному вході в блок. Ініціалізація виконується один раз при першому вході в блок.

Змінна, оголошена локально з класом пам’яті extern, є посиланням на змінну з тим же самим ім’ям, визначену глобально в одному з початкових файлів програми. Мета такого оголошення полягає в тому, щоб зробити визначення змінної глобального рівня видимим усередині блоку.

Приклад:

 1/* оголошення змінної i, що є ім'ям зовнішнього
 2   масиву довгих цілих чисел, на локальному рівні   */
 3
 4/* початковий файл  file1.c     */
 5main()
 6{ ...
 7
 8}
 9
10fun1()
11{
12   extern long i[]; ...
13}
14
15/*   початковий файл   file2.c     */
16long i[MAX]={0};
17fun2()
18{ ...
19
20}
21
22fun3()
23{ ...
24
25}

Оголошення змінної i[] як extern в приведеному прикладі робить її видимою усередині функції fun1. Визначення цієї змінної знаходиться у файлі file2.c на глобальному рівні і повинне бути тільки одне, тоді як оголошень з класом пам’яті extern може бути декілька.

Оголошення з класом пам’яті extern потрібне при необхідності використовувати змінну, описану в поточному початковому файлі, але нижчі по тексту програми, тобто до виконання її глобального визначення. Наступний приклад ілюструє таке використання змінної з ім’ям st.

Приклад:

 1main()
 2{
 3   extern int st[]; ...
 4}
 5
 6static int st[MAX]={0};
 7
 8fun1()
 9{  ...
10
11}

Оголошення змінної із специфікатором extern інформує компілятор про те, що пам’ять для змінної виділяти не вимагається, оскільки це виконано десь у іншому місці програми.

При оголошенні змінних на глобальному рівні може бути використаний специфікатор класу пам’яті static або extern, а так само можна оголошувати змінні без вказівки класу пам’яті. Класи пам’яті auto і register для глобального оголошення недопустимі.

Оголошення змінних на глобальному рівні - це або визначення змінних, або посилання на визначення, зроблені у іншому місці програми. Оголошення глобальної змінної, яке ініціалізує цю змінну (явно або неявно), є визначенням змінної. Визначення на глобальному рівні може задаватися в наступних формах:

  1. Змінна оголошена з класом пам’яті static. Така змінна може ініціалізувати явно константним виразом, або за умовчанням нульовим значенням. Тобто оголошення static int i=0 і static int i еквівалентні, і в обох випадках змінної i буде привласнене значення 0.
  2. Змінна оголошена без вказівки класу пам’яті, але з явною ініціалізацією. Такою змінною за замовчуванням привласнюється клас пам’яті static. Тобто оголошення int i=1 і static int i=1 будуть еквівалентні.

Змінна оголошена глобально видима в межах залишку початкового файлу, в якому вона визначена. Вище за свій опис і в інших початкових файлах ця змінна невидима (якщо тільки вона не оголошена з класом extern).

Глобальна змінна може бути визначена тільки один раз в межах своєї області видимості. У іншому початковому файлі може бути оголошена інша глобальна змінна з таким же ім’ям і з класом пам’яті static, конфлікту при цьому не виникає, оскільки кожна з цих змінних буде видимою тільки в своєму початковому файлі.

Специфікатор класу пам’яті extern для глобальних змінних використовується, як і для локального оголошення, як посилання на змінну, оголошену у іншому місці програми, тобто для розширення області видимості змінної. При такому оголошенні область видимості змінної розширяється до кінця початкового файлу, в якому зроблено оголошення.

У оголошеннях з класом пам’яті extern не допускається ініціалізація, оскільки ці оголошення посилаються на вже існуючі і визначені раніше змінні.

Змінна, на яку робиться посилання за допомогою специфікатора extern, може бути визначена тільки один раз в одному з початкових файлів програми.