Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Зубенко, Омельчук - Програмування. Поглиблений курс

.pdf
Скачиваний:
49
Добавлен:
07.03.2016
Размер:
4.72 Mб
Скачать

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

/**/***/*"/****//*,

///**/*/***///*//**/?

7.Яким буде подання в пам'яті літералів і якою буде довжина цих подань:

"\t\077"; "abc'1234'/*sos!*/\v"; " \x2514 3";

"\\\"\nLF"?

8.Яка структура C-програм?

9.Яка роль функції main у C-програмі?

10.Що таке препроцесор?

11.Що таке підключення файлів?

12.Що таке препроцесорні константи?

13.Яка роль заголовних файлів?

14.Що таке роздільна компіляція?

15.У чому полягає різниця між деклараціями й описом даних?

16.Які є класи пам'яті змінних і функцій?

17.Що таке час існування даного?

18.Що таке визначальний опис даного?

19.Чим відрізняється прототип від опису функції?

20.Що таке виклик функції?

21.Навести склад X-фрейму даних, що обробляє модифіковане тіло функції.

22.Що таке модифіковане тіло функції?

23.Що таке ініціалізація даних?

24.Що таке функція з побічним ефектом? Навести свої прикла- ди таких функцій.

25.Що таке локальна змінна?

26.Що таке глобальна змінна?

27.Що таке формальні параметри? Яка область їхньої дії?

28.Яке значення має змінна і у виділених точках програми:

int i=0; main()

{ auto int i=1; /* 1 */ {int i=2; /* 2 */

{ i+=1; /* 3 */

}

/* 4 */

}

/* 5 */

}?

29.Чи може дане у C-програмі бути одночасно і глобальним, і локальним?

30.Що виведуть такі фрагменти програм:

291

ПРОГРАМУВАННЯ

a) int f(int x, int y)

б) int f(int x, int y)

{ static int count=0;

{static int count=0;

count++;

count++;

printf("%d,",count);

printf("%d,",count);

return (x+y)/2;

return

}

(x>0?f(x/2,y/2):1);

main()

}

{ printf("%d\n",f(5,7));

main()

printf("%d\n",f(25,13));

{ printf("%d\n",f(5,7));

printf("%d\n",f(1024,-40));

} ?

} ,

 

 

 

3.2. Вирази

¾Структура виразів

¾Базові типи

¾Стандартні типи

¾Порядкові типи

¾Сумісність, зведення й узгодженість типів

Ключові слова: вираз, структура виразів, значення виразу, ліва й права асоці- ативність, l-вирази, r-вирази та f -вирази, вирази-присвоювання, таблиця операцій,

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

Основою будь-якої мови є терми конструкції, що подають реаль- ний чи абстрактний об'єкт. У мовах програмування терми назива- ються виразами. Вони є певним спеціалізованим варіантом Ω -термів. Як випливає з принципу типізації, мову програмування можна пода- ти у вигляді вежі типів зі структурою, яка описується об'єднаною Ω - системою її типів даних. Носій системи є універсумом усіх даних вежі типів, а сигнатуру Ω утворюють символи операцій та інтерфейсних і стандартних функцій, визначених на типах.

292

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

Виразами мови C називаються Ω-терми її системи типів.

Щоб з'ясувати, що таке вираз мови C (і будь-якої іншої), необхідно й достатньо описати всю її вежу типів разом із сигнатурою. Усі типи вежі поділяються на базові й похідні (рис. 3.1). Базові містяться безпо- середньо в машинних командах. Для процесора ці дані є цілісними (неділимими) і твірними усієї системи даних. З іншого боку, базові типи є наближеними комп'ютерними моделями цілої, дійсної й ком- плексних арифметик. Це визначає їхню надзвичайно важливу роль у запитах вхідних систем.

У даному підрозділі ми розглянемо базові й стандартні типи (окрім типу покажчиків і комплексних чисел). Комплексні типи (а їх шість різновидів) передбачені лише в С99. Комплексним змінним відпові- дають об'єкти зі значеннями двокомпонентними полями одного із трьох дійсних типів. Їхній опис і арифметику можна знайти в [133]. Решту похідних типів вивчатимемо в наступних підрозділах.

Спочатку конкретизуємо й розглянемо детальніше структуру вира- зів, а потім перейдемо до типів.

3.2.1. СТРУКТУРА ВИРАЗІВ

Вирази будуються з первинних виразів і викликів функцій за до- помогою операцій. Усі операції разом з їхньою сигнатурою й пріори- тетами наведено в табл. 3.5.

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

Якщо дві операції мають однаковий пріоритет, то операнди приєд- нуються до них залежно від напрямку асоціативності. Розрізняють ліву й праву асоціативність. Якщо вираз a b oc означає (a b)oc ,

то говорять про ліву асоціативність, а якщо a (b oc ) – то про праву. Правило асоціативності можна узагальнити:

Усі бінарні С-операції, за винятком присвоювань, мають ліву асоці- ативність.

Для унарних операцій діє правило:

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

293

ПРОГРАМУВАННЯ

Усі вирази мови С розподіляються на три види: l-, r- та f -вирази.

l - та r -вирази це конструкції, що за синтаксисом можуть бути відповідно лівим і правим операндами в операції присвоювання (див. підрозд. 2.1.2). f -виразами називаються конструкції, які використо-

вуються як імена функцій (англ. – function designator). Вони розгля- даються в підрозд. 3.6.1.

С-вирази = l -вирази+ r -вирази+ f -вирази

 

 

 

 

 

 

Типи даних

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

мови С

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Базові

 

 

 

 

 

 

 

 

 

 

Похідні

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Цілі

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Числові

 

 

 

 

 

 

 

 

 

 

Стандартні

 

 

 

 

 

 

 

 

Дійсні

 

 

 

 

 

 

 

 

 

 

 

Символьні

 

 

 

 

 

 

 

Порядкові

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Комплексні

 

 

 

 

 

 

 

 

 

 

Масиви

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Адреси

 

 

 

 

 

 

 

 

 

 

Структури

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Тип void

 

 

 

 

 

 

 

 

 

 

Обєднання

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Бітові поля

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Покажчики

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Потоки

 

 

 

 

 

 

 

 

 

 

 

Рис. 3.1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Таблиця 3.5. Операції мови C

 

 

 

 

 

 

 

 

 

 

 

 

Асоціативність

Пріоритет

 

 

Знак операції

 

 

Тип операції

1

()

виклик функції

 

 

 

 

 

 

 

Ліва

 

[]

індексація

 

 

 

 

 

Бінарна

 

 

 

 

.

 

взяття поля

 

 

 

 

 

Бінарна

 

 

 

 

 

 

 

-> розіменування поля

 

Бінарна

 

 

 

 

 

 

294

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

 

 

 

 

Закінчення табл. 3.5.

Пріоритет

 

Знак операції

Тип операції

Асоціативність

2

~ побітове заперечення

Унарні

Права

 

!

заперечення

-

 

 

* розіменування

-

 

 

& взяття адреси

-

 

 

+ + збільшення

-

 

 

-- зменшення

-

 

 

+, -

-

 

 

(тип) зведення типу

-

 

 

sizeof розмір типу

-

Ліва

3

*

множення

Мультипліка-

 

/

ділення

тивні

 

 

% залишок

 

 

4

+, -

Адитивні

 

 

 

 

 

5

<< зсув ліворуч

Побітові

 

 

>> зсув праворуч

 

 

6

<, >, <=, >=

Відношення

 

7

== рівність

Відношення

 

 

!=

нерівність

 

 

8

&

кон'юнкція

Побітова

 

9

^ додавання за mod 2

Побітова

 

10

| диз'юнкція

Побітова

 

11

&& кон'юнкція

Логічна

 

12

|| диз'юнкція

Логічна

 

13

?: умовна

 

Права

14

=, *=, /=, %=, +=, -=, &=,

Присвоювання

 

|=, >>=, <<=, ^=

 

 

15

, послідовне обчислення

 

Ліва

 

 

 

 

 

Приклад 3.15. Пріоритет і асоціативність операцій.

Вираз

Еквівалентний вираз

Коментар

a+b/c

a+(b/c)

Мультиплікативна

a*=b=c

a*=(b=c)

Права асоціативність

a-77+b

(a-77)+b

Ліва асоціативність

sizeof(double)*4

(sizeof(double))*4

Пріоритет sizeof вищий

*p->q

*(p->q)

Пріоритет -> вищий

*x++

*(x++)

Тут ++ – постфіксна й унарна

**x**y

(*(*x))*(*y)

Пріоритет розіменування вищий

**x++++*y

(*(*((x++)++)))*y

Тут ++ – постфіксна й має най-

 

 

вищий пріоритет, а унарна *

 

 

вища, ніж бінарна *

 

 

295

ПРОГРАМУВАННЯ

l-вирази:

<l-вираз>::=<змінна-стандартного-типу>|<індексований-вираз>| <вибір-компонентів>|<змінна-покажчик>| <розіменування-покажчика>|(<l-вираз>)

Значеннями l -виразів є адреси об'єктів певного типу з рівнем до- ступу до запису або до запису й читання. Однак потрібно взяти до уваги, що в деяких контекстах ці об'єкти не допускають запису. Не є l -виразами змінні з кваліфікатором const, імена масивів, функцій тощо. У табл. 3.6 перелічені всі l -вирази мови C.

l -вираз e

(e )

e.v

e v

*e

e [i]

Таблиця 3.6. l -вирази мови C

Значення

Коментар

Адреса змінної e

e стандартного типу

Значення виразу e

e l -вираз

Адреса поля v

e структура

Адреса поля v

e покажчик на структуру

Значення розіменованої змінної

e покажчик

Значення виразу * (e + i )

e покажчик

До операцій, що вимагають операндів l -виразів, належать: взят- тя адреси &, збільшення + + , зменшення і присвоювання.

Змінні стандартного типу розглядаються в підрозд. 3.2.3, індексо- вані вирази й вибір компонентів у підрозд. 3.4, 3.7, присвячених масивам і структурам, змінні-покажчики й розіменування покажчи- ків у підрозд. 3.5.

r -вирази найчисленніший за кількістю операцій і найскладні- ший вид виразів. Нагадаємо (див. підрозд. 2.1.2), що r -вирази нале- жать до X -арних U -функцій, які виробляють значення змінних. Оскільки всі змінні типізовані, то й значення кожного r -виразу типі- зовані, тобто належать одному з типів. Цей тип називається типом r -виразу (див. підрозд. 3.2.4).

<r-вирази>::=<первинний-вираз>|<вираз-присвоювання>| <постфіксний-вираз>|<унарний-вираз> |<бінарний-вираз>|<логічний-вираз>|<умовний-вираз>| |<послідовний-вираз>|<константний-вираз>

Розглянемо деякі види r-виразів. Унарні, бінарні й логічні вирази описуються в підрозд. 3.2.3.

296

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

З первинних виразів за допомогою операцій будуються всі решта:

<первинний-вираз>::=<l-вираз>|<константа>|(<вираз>)

Структуру l -виразів розглянуто вище. l -вирази як первинні віді- грають роль функцій читання, тому семантика їх залежить від кон- тексту. Діє правило: якщо наступною за l -виразом праворуч є опера- ція присвоювання, то l -вираз подає себе (тобто адресу), а якщо ні то функцію читання. З операційного погляду функція читання повер- тає значення об'єкта, адресу якого задає l -вираз.

Приклад 3.16. Нехай int i ціла змінна. Тоді в операції присвою- вання i=i+2 ліворуч ім'я i подає l -вираз, а праворуч функцію чи- тання. Якщо значенням змінної i в полі даних α є 5, то обчислення цього виразу на полі α приведе до значення 7 і заміни в ньому зна- чення змінної i на 7

Вирази-константи це лексеми-константи зі значеннями відповід- ного типу. Літерали при цьому мають тип символьного покажчика.

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

Приклад 3.17. Константи й вирази в дужках.

Нехай double a=1.0, b=-2.5; опис дійсних змінних з ініціалізацією.

Вираз

Тип

Значення

33

unsigned int

33

0777

unsigned int

51110

‘a'

unsigned char

97

0L

long

0

3.1428

double

3.1428

"3.1428"

*char

адреса символу

(a+b/2)

double

-0.25

((a+b)/2)

double

-0.75

Вирази присвоювання оновлюють значення змінних:

<присвоювання>::=<l-вираз> <операція-присвоювання> <r-вираз> <операція-присвоювання>::= =|*=|/=| %= |+=|-=|&=|

=|>>=|<<=|^=.

Вираз простого присвоювання e1 = e2 – це підстановки в операцію присвоювання на місце першого й другого операндів l - та r -виразів e1 та e2, типи яких збігаються або узгоджені. Узгодженими є всі арифме- тичні типи. Узгодженість решти типів розглядається у відповідних під-

297

ПРОГРАМУВАННЯ

розділах. Семантику операції присвоювання описано в підрозд. 2.1.2, а семантика виразу-присвоювання це семантика складеної функції:

1)спочатку обчислюються значення виразів e1 та e2;

2)за несумісності типів e1 та e2 значення e2 зводиться до типу e1;

3)отримані значення підставляються в операцію присвоювання на місце відповідних аргументів.

Про сумісність і зведення типів йдеться в підрозд. 3.2.4. Семантика складеного присвоювання О=', де О арифметична операція, зводить- ся до випадку простого присвоювання за формулою e1 = e1Oe2 .

Постфіксні вирази:

<постфіксний-вираз>::=<вираз-збільшення>|<вираз-зменшення> <вираз-збільшення>::=<l-вираз>++ <вираз-зменшення>::=<l-вираз>--

Типи й значення виразів e + + та e − − збігаються й дорівнюють значенню виразу e .

Суть цих операцій у побічному ефекті вони додають (віднімають) 1 до (від) значення e виразу після операції. У випадку покажчиків це означає їхнє пересування до наступного (попереднього) об'єкта в ОП даного типу.

Виклики функцій розглядаються в підрозд. 3.3.2, 3.6.2.

Умовні

вирази

є варіантом умовних термів і мають вигляд

e ?e1: e2,

де e

цілий вираз. Значення виразу задається умовним

термом (e 0 e1|e2).

Послідовні вирази мають вигляд e1,e2 . Семантика виразу полягає в послідовному обчисленні зліва направо виразів e1,e2 . Значення e1 відкидається, а значення e2 є значенням усього виразу. Операція асоціативна, тому можна послідовно об'єднувати в один єдиний дові- льну кількість виразів.

Константні вирази це вирази, які в процесі обробки компілятором замінюються на значення-константи. До них належать препроцесорні константні вирази в директивах #if та #еlif, цілі константні вирази, що використовуються при описі границь масивів, значень зліченних типів тощо та ініціалізаційні константні вирази в операторах опису змінних.

3.2.2. БАЗОВІ ТИПИ

Мова C містить кілька варіантів кожного з базових типів, але опе- раціями вони не відрізняються. Базові цілі типи зображені в мові C цілими константами й арифметичними операціями. Останні наведені в табл. 3.5 і розглядаються в підрозд. 3.2.3. Визначено кілька цілих

298

Розділ ІІІ. МОВИ ПРОГРАМУВАННЯ С ТА С++

типів різних розмірів. Константи цілого типу можуть записуватись у десятковій, вісімковій і шістнадцятковій системах із суфіксами u (U) для беззнакових цілих, l(L), ll(LL) для довгих цілих:

<ціла-константа>::=<десяткова-константа> <суфікс-цілого>| |<вісімкова-константа> <суфікс-цілого>| |<шістнадцяткова-константа> <суфікс-цілого>

<десяткова-константа>::=<ненулева-цифра>{<цифра10 >} <вісімкова-константа>::=0{<цифра8 >}

<шістнадцяткова-константа>::=(0x|0X)<цифра16 >{<цифра16 >}

<суфікс-цілого>::=<cуфікс-беззнакового>[<суфікс-довгого>] | |<суфікс-довгого>[<cуфікс-беззнакового>] <cуфікс-беззнакового>::=u | U

<суфікс-довгого>::=l | L| ll| LL

Для визначення основи системи числення цілої константи необхід- но послідовно виконати п. 1-3 такого правила:

1)Якщо константа має один із префіксів 0x, 0X, то вона шістна- дцяткова.

2)Якщо константа має префікс 0, то вона вісімкова.

3)Це десяткова константа?

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

Приклад 3.18. Цілі константи: 10U десяткове беззнакове ціле; 25uL десяткове беззнакове довге; 1LL десяткове довге-довге; 0L вісімковий довгий нуль 08 ; 037 вісімкове; -0777 від'ємне вісімкове

-7778 ; -0x25 від'ємне шістнадцяткове - 2516

УС99 дійсні константи записуються або за допомогою мантиси з точкою (не обов'язково нормалізованою), або цілого з порядком, або мантиси з порядком:

<дійсна-константа>::=<десяткова-дійсна-константа> | <шістнадцяткова-дійсна-константа> <десяткова-дійсна-константа>::=

299

ПРОГРАМУВАННЯ

<десяткова-константа-з-0> <експонента> [<суфікс-дійсного>] | <дійсне-з-фіксованою-точкою>[<експонента>][<суфікс-дійсного>] <десяткова-константа-з-0>::=<десяткова-константа> | 0 <дійсне-з-фіксованою-точкою >::=[<десяткова-константа-з-0>]. \ [<десяткова-константа-з-0>] <експонента>::=(e|E)[<знак>]<десяткова-константа> <знак>::=+|-

<cуфікс-дійсного>::=f|F|l|L

У числах із фіксованою точкою не можуть бути одночасно відсутні й ціла, і дробова частини. Суфікси виділяють константи типів float та long double. Відсутність суфікса означає, що тип константи double.

Для отримання від'ємної дійсної константи необхідно, як і у випад- ку цілих, застосувати операцію унарний мінус.

Три дійсні типи відрізняються тільки точністю й розміром порядку. Якщо точність чисел не принципова й необхідно економити пам'ять (напр., у таблицях), то використовують тип float.

Приклад 3.19. Десяткові дійсні константи 0.f(=0.0), 1.0f(=1.0),

.25 f(=0.25) належать до типу float, константа 1e-2L (=0.01) – до

типу long double, константа 1.0e+25 (=10 25 .0) до типу double

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

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

У С99 передбачено заголовний файл float.h, в якому розміщують- ся граничні значення для дійсних констант у даному компіляторі. У табл. 3.7 наведено деякі з них.

На відміну від стандарту С89, стандарт С99 дозволяє використову- вати також шістнадцяткові дійсні константи. Формат схожий на фо- рмат десяткових дійсних. Таким константам передує шістнадцятко- вий префікс 0x, 0X. Експонентою є двійкова експонента вигляду

p ±n16 зі значенням 2n , де n =n16 .

Приклад 3.20. Шістнадцяткові дійсні константи:

0X1.0(=1.0), 0x19.(=25.0), 0XAp-2(10*2 2 =2.5)

300