Пріоритет і порядок виконання.
Зміст операції
Назва
Асоціативність

() [] . ( ++ - - (пост)
Первинні
(

~ ! * &
+ + - - sizeof
Приведення типу
Унарні
(

* / %
Мультиплікативні
(

+ -
Адитивні
(

<< >>
Зсув
(

< > <= >=
Відношення
(

= = !=

(

&
Порозрядне ?
(

^
Порозрядне викл. АБО
(

?
Порозрядне АБО
(

&&
Логічне ?
(

¦
Логічне АБО
(

?:
Умовна
(

= *= /= %= += - = <<= >>= &= ?= ^=
Просте і складне присвоєння
(


Послідовне обчислення
(


Зауваження: Мультиплікативні, адитивні і порозрядні операції мають властивість комутативності (результат обчислення виразу не залежить від порядку виконання цих операцій). Тому компілятор сам визначає порядок обчислення таких виразів.
Приклади
Вираз Групування операцій
a & b¦ c (a & b)¦ c
a = b ¦ с a = (b ¦ c)
q&& r ¦ s - - (q&& r) ¦ (s - -)

p = = 0 ? р + = 1: р + =2 (p = = 0 ? р + = 1: р) + =2
Для усунення цього рекомендується
(p = = 0) ? (р + = 1): (р + =2)
4.6. Побічні ефекти
add (i+1, i=j+2);
і=0;
int i, a[0]; a[i1+]=i; a[0]=0 ?
1 ?
Для операції присвоєння порядок обчислення аргументів не визначено.
Невдалий порядок пріоритету:
операції зсуву і порозрядні (вони мають нижчий пріоритет, ніж інші).
a=b & 0FF+5 ( a=b & (0FF+5)
a+c>>1 ( (a+c)>>1
a * + (b*c) (b?c) 1)b*c
2)a*( )
, в переліку аргументів функції не є операцією послідовного обчислення.
іnt x, y, z, f( );
z= x> y ¦f (x, y);
підвищення ефективності за рахунок розташування найбільш вірогідних умов як перший операнд.
вставка перевірок, при неістинності яких наступні дії не відбуваються
if ((!feof (pf)) && (c=getc (pf))…
Контрольні точки (де усі попередні обчислення та побічні ефекти гарантовано обчислені):
кінець повного виразу (виразу, який не є частиною іншого виразу)
кінець ініціалізуючого виразу для змінної auto?
кінець виразів, які керують виконанням операторів if, switch, for, do, while і вирази в операторі return.
5. ОПЕРАТОРИ
5.1. Вступ.
Оператори мови Сі керують процесом виконання програми.
(наявні всі керуючі конструкції структурного програмування):
1. Пустий оператор;
2. Складений оператор(блок);
3. Оператор - вираз;
4. Умовний оператор if;
5. Оператор покрокового циклу for;
6. Оператор циклу з передумовою while;
7. Оператор циклу з постумовою do;
8. Оператор продовження continue;
9. Оператор- перемикач switch;
10. Оператор- розриву break;
11. Оператор переходу goto;
12. Оператор повернення return.
Зауваження:
В мові Сі відсутні булівські вирази як самостійний клас виразів.
В тілі деяких операторів можуть міститися інші оператори.
Складений оператор обмежується {}. Всі інші оператори закінчуються крапкою з комою – ознакою закінчення оператора.
Перед любим довільним оператором мови Сі може бути записана мітка з імені і двокрапки.
Програма на мові Сі виконується послідовно, оператор за оператором, за виключенням випадків, коли якийсь оператор явно перадає керування в іншу частину програми, наприклад, при виклику функції чи поверненні з неї.
5.2. Пустий оператор
Синтаксис:
Дія: Виконання пустого оператора не змінює стану програми.
Пустий оператор задовольняє вимогам синтаксису.
Коли ніяких дій не потребується:
for (i= Ø; i< 1 Ø; a[i+1]=0)
;
Пустий оператор може бути помічений міткою.
Наприклад: {


lable: ;
} – не є оператор.
5.3. Складений оператор
Синтаксис:
{
[<оголошення>]
[<оператор>]
Дія: Послідовне виконання операторів, що містяться у складеному операторі за винятком тих випадків, коли якийсь оператор явно передає керування в інше місце програми.
Будь-який оператор в середині складеного оператора може бути помічений. Можлива передача керування по мітці в середину складеного оператора. Однак, якщо складений оператор містить оголошення змінних з ініціалізацією, то при вході в блок по мітці ініціалізація виконана не буде.
Можна поставити мітку і на сам складений оператор, якщо це не оператор, що являється тілом функції.
5.4. Оператор- вираз
Синтаксис:
<вираз>;
Дія: <вираз> обчислюється у відповідності з правилами викладеними у розділі 4 «Вирази».
Відмінність: - значення виразу не використовуються.
Крім того, він може бути записаний тільки там, де по синтаксису допустимий оператор.
5.5. Умовний оператор if
Синтаксис:
іf (<вираз>)
<оператор 1>
[else
<оператор 2>]
Дія: Тіло умовного оператора if виконується в залежності від значення <вираз>.
Якщо <вираз> False, а else опущено, то керування передається на оператор, що слідує в програмі за оператором if;
Вкладеність
Оператор if може бути вкладений в <оператор 1> або <оператор 2> іншого оператора if. Рекомендується використовувати в цьому випадку фігурні дужки, що обмежують <оператор 1> і <оператор 2>.
Якщо {} відсутні, то компілятор асоціює кожне ключове слово else з найближчим оператором if, у якого відсутнє else.
На if можна ставити мітку, на else – ні.
Однак можна поставити мітку на <оператор 2>.
Приклади:
if(i> 0 ) if(i> 0)
if(j>i) {
x=j; if(j>i)
else x=j;
x=i; }
else
x=i;
5.6. Оператор покрокового циклу for
Синтаксис:
for ([<початковий_вираз>];
[<умовний_вираз>];
[<вираз_приросту>])
<оператор>
Дія: Виконується доти, поки <умовний_вираз> не стане False. <початковий_вираз> і <вираз_приросту> застосовуються, звичайно, для ініціалізації і модифікації параметрів циклу та інших значень.
Порядок роботи:
Обчислюється <умовний_вираз> і аналізується:
Якщо <умовний_вираз>True (не 0), то виконується тіло оператора. Потім <вираз_приросту>, якщо він є, і процес продовжується.
Якщо <умовний_вираз> опущений, то його значення приймається за істину і далі як в п.1). В цьому випадку цикл можна завершити тільки за допомогою виконання в його тілі операторів break, goto, return.
Якщо <умовний_вираз> False, (0), то for закінчується і керування передається наступному за ним оператору. Завершити цикл можна і за допомогою break, goto, return в тілі циклу.
Оператор циклу з передумовою while
Синтаксис:
while(<вираз>)
<оператор>.
Дія: Тіло оператора while виконується доти, поки значення <виразу> не стане 0.
Перед кожним наступним виконанням тіла циклу <вираз> обчислюється заново.
Завершити дію циклу можна за допомогою операторів break, goto, return.
Оператор циклу з постумовою do
Синтаксис:
do <оператор>
while (<вираз>).
Те саме, що і для while.

Оператор продовження continue
Синтаксис:
сontinue;
Дія: передає керування на наступну ітерацію в операторах циклу do, for, while. Може з’явитися тільки в тілі цих операторів.
В операторах циклу do i while наступна ітерація починається з обчислення <виразу – приросту >, а потім відбувається обчислення умовного виразу.
Приклад: while(i - - >0)
{
x=f(i);
if (x = = 1)
continue;
else
y=x*x;
}.
5.10. Оператор перемикач switch
Синтаксис:
Switch (<вираз>)
{
[<оголошення>] константа
……..
[case < константний_вираз >:]
[<оператор>]
……… варіанта
[case < константний_вираз >:]
[<оператор>]
……..
[default:
<оператор>]
}
Дія: Вибір одного з альтернативних шляхів виконання програми.
Конструкція case < константний вираз >: default синтаксично являє собою мітки операторів.
Значення констант, варіантів повинні бути унікальними всередині тіла оператора – перемикача
<вираз> повинен мати цілочисельний тип.
Для виходу з тіла перемикача застосовують звичайний оператор break. (Поширена помилка – відсутність break).
Зауваження! 1) Ініціалізатори, які розміщені в блоці не будуть виконані
2) Оператор в тілі перемикача може бути помічений багатьма мітками.
5.11. Оператор розриву break
Синтаксис: break;
Дія: перериває виконання операторів do, for, while, switch. Може з’явитися тільки в цих операторах.
Зауваження. Якщо break записаний всередині вкладених операторів do, for, while, switch, то він завершить тільки оператор, що його безпосередньо охоплює.
Якщо потрібно завершення більш ніж одного рівня вкладеності, то треба застосувати goto і return.
5.12. Оператор переходу goto
Синтаксис: goto <мітка>
.
.
.
<мітка>: <оператор>
Дія: передає керування на <оператор>, помічений <міткою>. – звичайним ідентифікатором.
Область дії мітки обмежується функцією, в якій вона визначена: 1) в межах функції мітки унікальні; 2) не можна передати керування по goto в іншу функцію.
Можна увійти в блок, тіло циклу, умовний оператор, оператор – перемикач по мітці.
Не можна передати керування на конструкції case і default в тілі перемикача.
5.13. Оператор повернення return
Синтаксис:
return [<вираз>];
Дія: Закінчує виконання функції, в якій він міститься і передає керування у функцію, яка робила виклик. Керування передається в точку викликаючої функції, що безпосередньо розміщена за оператором виклику.
Значення <виразу>, якщо він заданий, обчислюється, приводиться до типу, оголошеного для функції, що містить оператор return, і повертається у функцію, яка робила виклик.
Якщо <вираз> опущений, то значення, що вертається невизначене.
Якщо оператор return відсутній в тілі функції, то керування передається після виконання останнього оператора цієї функції. Значення, що повертається невизначене. Таку функцію треба явно оголошувати з типом void.
ФУНКЦІЇ
6.1. Вступ.
Функція – це сукупність оголошень та операторів, призначена для виконання деякої окремої задачі.
Кількість функцій у програмі не обмежується.
Будь-яка програма на мові Сі містить хоча б одну функцію. Це так звана головна функція з іменем main.
Виклик функції передає керування від викликаючої функції до тої, що викликається. Значення фактичних аргументів, якщо вони є передаються у функцію, що викликається. При виконанні оператора повернення return у функції що викликається, керування та значення що повертається (якщо воно є) передаються у викликаючу функцію.
6.2. Визначення функції.
Синтаксис(старий):
[<специфікація класу пам’яті>] [<специфікація типу>]
<описувач> ([<список параметрів>]) [<оголошення параметрів>]
<тіло функції>.

<специфікація типу> в сукупності з <описувачем> визначає тип значення, що повертається, та ім’я функції.
<список параметрів> - список (можливо пустий) імен формальних параметрів, значення яких передається функції під час виклику.
<оголошення параметрів> - задає ідентифікатори і типи формальних параметрів.
<тіло функції> - складений оператор, що містить оголошення локальних змінних і оператори.
Синтаксис(сучасний):
[<специфікація класу пам’яті>] [<специфікація типу>]
<описувач> ([<список оголошень параметрів>])
<тіло функції>
<список оголошень параметрів> аналогічний списку типів аргументів в прототипі функції.
Він містить оголошення формальних параметрів через кому.
Однак, якщо в прототипі область дії ідентифікаторів обмежена цим же прототипом, то у списку оголошень параметрів ідентифікатори іменують формальні параметри даної функції. Їх область дії – тіло функції.

Класи пам’яті
Модифікатори типу функції
Типи значень, що повертаються.
Синтаксис, за допомогою якого задається тип значення, що повертається функцією, описаний у розділі 3.5 «Оголошення функції».
Зауваження:
Функція може повертати значення будь-якого типу, крім масиву чи функції; вона може, зокрема, повертати покажчик на будь-який тип, включаючи масив і функцію.
Тип значення, що повертається, який задається у визначенні функції, повинен відповідати типу значення що повертається у всіх оголошеннях цієї функції, якщо вони є у програмі.
Для виклику функції з типом значення що повертається int не обов’язково її попередньо оголошувати чи визначати.
Функції з іншими типами значень що повертаються повинні бути визначені чи оголошені до того як вони будуть викликані.
Значення що повертається, виробляється при виконанні оператора повернення return, що містить вираз.
Вираз обчислюється, приводиться до типу значення що повертається і повертається в точку виклику функції.
Якщо return відсутній чи не містить виразу, то значення що повертається не визначено.
Формальні параметри.
Формальні параметри – це змінні, які приймають значення передані функцією при виклику у відповідності з порядком слідування їх імен у списку параметрів.
Компілятор виконує перетворення по замовчуванню окремо над типом кожного формального параметру і над типом кожного фактичного параметру.
Змінна кількість параметрів (…) (а,b,…)
Тіло функції.
Тіло функції являє собою складений оператор, чи блок. Він містить оператори, які визначають дію функції, і оголошення змінних, що використовуються в цих операторах.
Усі змінні, оголошені у тілі функції мають клас auto, але можна явно присвоїти їм інший клас пам’яті.
При виклику функції виділяється пам’ять для їх локальних змінних і, якщо вказано, відбувається їх ініціалізація. Керування передається першому оператору складеного оператора. Виконання продовжується до тих пір, поки не зустрінеться оператор return, або кінець тіла функції (складеного оператора). Керування повертається в точку виклику функції.
Оголошення функції.
Оголошення функції розглянуто в розділі 3.5.
Однак, функція може бути оголошена неявно, по контексту її виклику. Неявне оголошення має місце кожен раз, коли функція викликана без попереднього оголошення або визначення. Тоді вважається що повертається значення типу int.
Основне призначення попереднього оголошення полягає в задані типів і числа аргументів, що очікуються у виклику функції.
Якщо попереднє оголошення відсутнє, то програміст сам повинен слідкувати за відповідністю типів між фактичними аргументами і формальними параметрами.
Виклик функції.
Виклик функції передає керування і фактичні аргументи (якщо вони є) заданій функції.
Синтаксис:
<вираз> ([<список виразів>])
<вираз> обчислюється, і його результат інтерпретується як адреса функції. Вираз повинен мати тип функція.
<список виразів> - перелік фактичних аргументів, що передаються функції (може бути пустим).
Викликана функція працює з копіями фактичних аргументів (роз’яснити наслідки).
Передача керування – на перший оператор тіла функції. return повертає у точку виклику керування і, можливо, значення.
Якщо return відсутній, керування повертається по досягненні } тіла функції. В цьому випадку значення що повертається не визначено.
Зауваження:
Порядок обчислення виразів, що являють аргументи виклику функцій, не визначений у мові Сі. Тому можливі побічні ефекти. Гарантується тільки те, що всі побічні ефекти будуть враховані до передачі керування у функцію що викликається.
<вираз> - повинен посилатися на функцію.
Це значить:
Функція може бути викликана не тільки по ідентифікатору, але і через довільний вираз, що має тип покажчика на функцію.
int (*p funk(int x);
int funk(int x);
p funk=&funk; /* & - необов’язковий */
(*p funk) (3); або p funk(3);

6.4.1. Фактичні аргументи.
Фактичні аргументи можуть бути довільним значенням базового типу, структурою, об’єднанням або покажчиком. Усі фактичні аргументи передаються по значенню.
Масиви і функції не можуть бути передані як параметри, але можуть передаватися покажчики на ці об’єкти. (масиви і функції передаються по посиланню).
Значення фактичних аргументів копіюються у відповідні формальні параметри. Функція використовує тільки ці копії, не змінюючи самі змінні, з яких ці копії були зроблені.
Покажчики забезпечують можливість доступу не до копій значень, а до самих змінних.
Фактичні аргументи (вирази у виклику функції) обчислюються і повертаються наступним чином:
1) Якщо є прототип, то при виклику функції виконуються перетворення по замовчуванню над типом кожного фактичного аргументу, заданого у списку типів аргументів. Потім фактичні аргументи приводяться до отриманого перетвореного типу.
Незалежно від аргументу, тип відповідного формального параметру у списку параметрів функції також перетвориться по замовчуванню.
Потім отриманий тип фактичного аргументу порівнюється з типом відповідного формального параметра. У випадку невідповідності ніякого перетворення не відбувається , а компілятор видає таке ж повідомлення, як для виразу присвоєння, коли типи лівого і правого операнда не співпадають.
Якщо прототип відсутній, то перетворення по замовчуванню відбуваються окремо для кожного аргументу.
Якщо список типів аргументів завершується (…) і задано більше фактичних аргументів, ніж імен у списку, то зайві фактичні аргументи перетворюються по замовчуванню.
Якщо список типів аргументів не завершений (…), а передається більше фактичних аргументів ніж оголошено імен у списку, то видається повідомлення.
Якщо у списку типів аргументів - void - то компілятор очікує відсутності фактичних аргументів у виклику функції і відсутність формальних параметрів у визначенні функції. Якщо одна з цих умов порушена, то компілятор мови Сі видає повідомлення.
6.4.2. Виклик функції зі змінною кількістю аргументів
6.4.3. Рекурсивні виклики
Компілятор не обмежує число рекурсивних викликів однієї функції. auto, register – виділяються комірки. Static, extern (на внутрішньому рівні ) – не виділяються.
7. ДИРЕКТИВИ ПРЕПРОЦЕСОРА І ВКАЗІВКИ КОМПІЛЯТОРУ.
7.1. Вступ.
Препоцесор – макропроцесор, що використовується для обробки вихідного файлу на нульовій фазі компіляції. Компілятор сам викликає препроцесор, але препроцесор може бути викликаний і автономно.
Директиви препроцесора - інструкції записані у вихідному тексті програми на мові Сі і призначені для виконання препроцесором мови Сі.
Директиви препроцесора застосовуються в основному для того, щоб полегшити модифікацію вихідних програм і зробити їх більш незалежними від особливостей різних реалізацій компілятора мови Сі, різних комп’ютерів і операційних середовищ.
Директиви препроцесора дозволяють замінити лексеми в тексті програми деякими значеннями, вставити у вихідний файл вміст іншого вихідного файлу, заборонити компіляцію деякої частини вихідного файлу і т.д.
Препроцесор Сі розпізнає наступні директиви:
# define #else # if # ifndef # line
# elif #endif # ifdef # include # undef
# - ознака директиви (повинен бути першим у рядку, що містить директиву)
[?]#[?]
? - пробільний символ
Деякі директиви можуть мати аргументи.
Директиви можуть бути записані в довільному місці файлу. Але їх дія – від точки програми, де вони записані до кінця вихідного файлу.
Вказівки компілятору, або прагми, являють собою інструкції, що записуються у вихідному тексті програми і призначені для керування діями компілятора мови Сі в певних ситуаціях.
Існує можливість отримати протилежний текст програми після обробки препроцесора до початку власне компіляції.
7.2. Іменовані константи та макровизначення
Директива # define – звичайно застосовується для заміни у програмі часто вживаних констант, ключових слів, операторів і виразів, ідентифікаторів і виразів осмисленими ідентифікаторами.
Ідентифікатори, що замінюють числові або текстові константи або довільну послідовність символів називаються іменованими константами.
Ідентифікатори, які представляють деяку послідовність дій, задану операторами або виразами мови Сі, називаються макровизначеннями. Макровизначення можуть мати аргументи.
Звертання до макровизначень у програмі називається макровикликом.
Директива # undef відміняє поточне визначення іменованої константи. Коли визначення відмінене, іменованій константі може бути надане інше значення. Однак, багатократне повторення визначення з одним і тим самим значенням не вважається помилкою.
Макровизначення нагадує по синтаксису виклик функції.
Переваги і недоліки.
Існує можливість задавати визначення іменованих констант не тільки у вихідному тексті, але і в командному рядку компіляції.
Існує ряд наперед визначених ідентифікаторів, які не можна використати в директивах # define і # undef в якості ідентифікаторів.
7.2.1. Директива # define
Синтаксис:
# define <ідентифікатор> <текст>
# define < ідентифікатор> (<список_параметрів>) <текст>
Директива # define замінює всі входження < ідентифікатора> у вихідному файлі на <текст> (макропідстановка).
< ідентифікатор> замінюється тільки тоді, коли він представляє окрему лексему (якщо < ідентифікатор> частина рядка, або іншого ідентифікатора, то він не замінюється).
Якщо за < ідентифікатором> слідує <список_параметрів>, то директива визначає макровизначення з аргументами.
<текст> - набір лексем, таких як ключові слова, константи, ідентифікатори чи вирази.
<текст> від < ідентифікатора> або <списку_параметрів> повинні виділяти один або більше пробільних символів.
Для продовження <тексту> на інший рядок - \ ENTER.
<текст> може бути опущений.
У цьому випадку усі екземпляри <ідентифікатора> будуть видалені з вихідного тексту програми. Але сам < ідентифікатор> розглядається як визначений і може бути перевірений директивами.
<список_параметрів>, якщо він заданий містить один чи більше ідентифікаторів, відокремлених комами. Ідентифікатори у списку повинні відрізнятися один від одного. Їх область дії обмежена макровизначенням, в якому вони задані.
Імена формальних параметрів і <текст> відмічають позиції, в які повинні бути підставлені фактичні аргументи макровиклику. Кожне ім’я формальних параметрів може з’являтися в <тексті> довільне число разів.
У макровиклиці за <ідентифікатором> у круглих дужках через список фактичних аргументів, що відповідають формальним параметрам з <списоку_параметрів>.
<текст> модифікується шляхом заміни кожного формального параметра на відповідний фактичний аргумент. Списки фактичних аргументів і формальних параметрів повинні містити одне й те ж саме число елементів.
При розширенні макросів ніяких обчислень чи перетворень типів не відбувається (підстановка чисто текстова).
У <тексті> в директивах # define можуть бути вкладені імена інших макровизначень чи констант.
Їх розширення відбувається тільки при розширенні <ідентифікатора> цього <текста>, а не при його визначенні директивою # define.
Після виконання макропідстановки, отриманий рядок знову переглядається для пошуку інших імен констант і макровизначень. При повторному перегляді не приймається до уваги ім’я раніше виконаної макропідстановки.
Інакше # define х х привела б до зациклювання препроцесора.
MULT (a, b) ((a)*(b)) - необхідність круглих дужок
Max (x, y) (((x)>(y))?(x): (y))
Побічні ефекти
Max (i, s[i + +]) ((i)>(s[i + +])) ?(i) : (s[i + +]))
операнди можуть бути обчислені
в довільному порядку. Тому результат
виразу непередбачений.
MULT (3+4, 4+5)
7.2.2. Склеювання лексем і перетворення аргументів макровизначень
# # - препроцесорна операція склеювання лексем.
Для склеювання лексем їх потрібно відокремити # # (зліва і справа від # # допустимі символи пропуску)
Препроцесор об’єднує такі лексеми в одну
# define Var (i, j) i # # j
Var (x, 6) x6
Символ # перед аргументом макровизначення вказує на необхідність перетворення його в символьний рядок. При макровиклиці # <формальний_параметр> замінюється на «<фактичний аргумент>».
Макровизначення Trаce дозволяє друкувати за допомогою стандартної функції printf значення змінних типу int у форматі <ім’я> = <значення >.

# define Trаce (flag) print (# flag “= % d \ n”, flag)
val=10
Trаce (val) printf (“val ”“= % d ”, val)
При макровиклику спочатку відбувається макропідстановка всіх аргументів макровиклику, а потім їх підстановка в тіло макровизначення:
main
{
# define AB “1”
# define A “2”
# define B “3”
# define Concat(p,q) p # # q
Print (Concat (A,B) “\ n”);
}
7.2.3. Директива # undef
Синтаксис:
# undef <ідентифікатор>
Скасовує дію поточного визначення # define для <ідентифікатора>. Виконується звичайно у парі з define для створення області програми, у якій ідентифікатор визначений. Не є помилкою застосування # define до ідентифікатора, який не був раніше визначений (або його дія була скасована).
7.3. Включення файлів
Синтаксис:
# include “ім’я шляху”
# include <ім’я шляху>
# include - включає вміст файлу і ім’я шляху якого задане, в поточний файл, який компілюється.
Наприклад: спільні для деяких вихідних файлів визначення іменованих констант і макровизначень можуть бути зібрані в одному файлі, що включається.
Рекомендації по вмісту заготовочних файлів:
Що рекомендується включати
Визначення типів struct point {int x, y;}
Оголошення функцій
Оголошення даних extern int a;
Визначення констант const float pi = 3.14;
Визначення іменованих констант
Визначення Макровизначення
Директиви включення файлів # include < >
Коментарі
Ніколи не треба включати:
Визначення функцій
Визначення даних int a=2;
Препроцесор обробляє заголовочний файл таким же чином , як у ситуації коли цей файл цілком входить у склад вихідного файла в точці, де записана директива # include.
Ім’я шляху представляє собою ім’я файлу, якому може передувати ім’я пристрою і каталогу (за правилами ОС).
Варіант 1: “ ” – "4"
Якщо ім’я шляху задано повністю (однозначно), то файл шукається тільки у каталозі заданому в імені шляху.
Якщо ім’я шляху неповне, то препроцесор шукає файл в поточному робочому каталозі (там де знаходиться файл в якому є директива # include).
Якщо # include вкладені, то пошук ведеться в поточних робочих каталогах, що відповідають охоплюючим файлам з глибини назовні.
Рівень вкладеності залежить від реалізації компілятора.
В кінці препроцесор продовжує пошук в каталогах, вказаних в командному рядку компілятора і нарешті якщо < >, то каталоги в кожному рядку компілятора, а потім в стандартних каталогах.
7.4. Умовна компіляція
Розглядаються директиви, які керують умовною компіляцією. Вони дозволяють виключити з процесу компіляції частини вихідного файлу шляхом перевірки умов (константних виразів).
7.4.1. Директиви # if, # elif, # else, # endif
Синтаксис:
# if <обмежений_ константний_ вираз>
[<текст>]
[# elif <обмежений_ константний_ вираз>
<текст>]
[# elif <обмежений_ константний_ вираз>
<текст>]
.
.
.
[# else
<текст>]
# endif
Зауваження: 1) кожній директиві # if у тому ж вихідному файлі повинна відповідати директива # endif.
2) Між # if та # endif допускається довільна кількість директив # elif (в тому числі жодної) і не більше однієї директиви # else.
3) Якщо # else присутня, то між нею і директивою # endif на даному рівні вкладеності не повинно бути інших директив # elif.
<текст> - може містити директиви препроцесора, в тому числі і умовної компіляції.
Препроцесор вибирає ділянку текста для обробки на основі обчислення <обмеженого_константного_виразу>. Вибирається <текст>, який слідує за <обмеженим_константним_виразом> зі значенням істина (не нуль) аж до найближчої директиви # elif, # else, # endif, асоційованої з даною директивою # if, # elif.
Якщо ні один обмежений константний вираз не істинний то препроцесор вибирає <текст>, що слідує за директивою # else. Якщо ж # else відсутнє, то ніякий текст не вибирається.
Обмежений константний вираз не може містити код операцій, операцію приведення типу, плаваючі константи, перелічувані константи і т.д., але може містити препроцесорну операцію defined (<ідентифікатор>).
Ця операція дає істине (ненульове) значення, якщо заданий ідентифікатор в даний момент визначений. В протилежному випадку – нуль.
Нагадування: (Ідентифікатор визначений без значення, розглядається як визначений).
Операція defined може застосовуватися у складному виразі в директиві # if неоднократно:
# if defined (ааа) ¦ defined (ввв)
Приклади:
# if defined (CREDIT)
credit( );
# elif defined (DEBIT)
debit ( );
# else
# print error( );
# endif
# if a>5
# defined res 1
# else
# defined res 0
# endif
7.4.2. Директиви # ifdef : # ifndef
Синтаксис:
# ifdef <ідентифікатор>
# ifndef< ідентифікатор>
Аналогічно директиві # if, за директивою # ifdef і # ifndef може слідувати набір директив # elif і директива # else. Набір повинен бути завершений # endif.
# ifdef і # ifndef еквівалентні застосуванню # if з операцією
defined (<ідентифікатор>)
# ifdef a ? # if defined (a)
# ifdef a ? # if ! defined (a)
Рекомендується застосовувати для сумісності зі ?
7.5. Керування нумерацією рядків
Синтаксис:
# line <константа> [«ім’я_файла»]
Директива повідомляє компілятору мови Сі про зміну імені вихідного файлу і порядку нумерації рядків.
Ці зміни відбиваються тільки на діагностичних повідомленнях компілятора:
Після обробки чергового рядка, лічильник номерів рядків збільшується на одиницю.
<константа> в директиві # line – може бути довільною цілою константою. Ім’я файлу – довільна комбінація символів.
7.6. Вказівки компілятору Сі
Синтаксис:
# pragma <послідовність символів> - задає інструкцію компілятору і, можливо, аргументи.
7.7. Псевдозмінні
Псевдозмінні являють собою зарезервовані іменовані константи, які можна використовувати в будь-якому вихідному файлі.
_LINE_ - номер поточної стрічки вихідного файла – десяткова константа (перша стрічка має номер 1)
_FILE_ - ім’я компільованого файла – символьний рядок. Значення цієї змінної змінюється кожен раз при обробці # include #line, а також по завершенню включеного файла.