3.4.4 Оголошення об’єднання
Об’єднання дозволяє в різні моменти часу зберігати в одному об’єкті значення різного типу. В процесі оголошення об’єднання з ним асоціюється набір типів значень, які можуть зберігатися в одному об’єднанні. В кожен момент часу об’єднання може зберігати значення тільки одного типу з набору. Контроль за тим, якого типу значення зберігається в даний момент в об’єднанні, накладається на програміста.
Синтаксис:


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

{
int svar;
uisigned uvar;
}number;
3.4.5 Оголошення масиву
а) [<специфікація типу>] <описувач>[<конкретний вираз>];
б) [<специфікація типу>] <описувач>[ ];
Масив дозволяє зберігати як одне ціле послідовність змінних однакового типу. Оголошення масиву визначає тип елементів масиву і його ім’я. Воно може визначати також число елементів в масиві. Змінна типу масив приймає участь у виразах як константа покажчик на значення заданого специфікацією типу. Якщо специфікація опущена, то мають на увазі тип int. Якщо <описувач> являє собою ідентифікатор, то оглошується масив елементів специфікованого типу. Якщо ж <описувач> являє собою більш складну конструкцію, то кожен елемент массиву має тип, заданий сукупністю <специфікація типу> і частиною описувача, що залишається. Це може бути довільний тип, крім типів Void і функція. Таким чином, елементи масиву можуть мати базовий, перелічуваний, структурний тип, бути об’єднанням, покажчиком або, в свою чергу, масивом.
Константний вираз у квадратних дужках визначає число елементів у масиві. Індексація елементів масиву починається з нуля. Таким чином, останній елемент масиву має індекс на одиницю менший, ніж число елементів масиву.
Форма а) застосовується, якщо в оголошенні масиву має місце ініціалізатор, або масив оголошується як формальний параметр функції. Однак для багатовимірного масиву може бути опущена тільки перша розмірність.
Багатовимірний масив, або масив масивів оголошується шляхом задання послідовності константних виразів в квадратних дужках, які слідують за описувачем:
<специфікація типу> <описувач> [<константний вираз>]
[<константний вираз>]...;
Елементи масиву з першого по останній розміщуються в послідовних комірках пам’яті, в порядку зростання адрес. Між елементами масиву розриви в пам’яті відсутні. Елементи багатовимірного масиву запам’ятовуються по рядках (останній індекс змінюється швидше передостаннього).
Для доступу до масиву застосовується індексний вираз.
Приклади
Struct char * name [20];
{ int iarray [10];
float x,y; float matrix [10][15];
}complex [100];
Зауваження! Контроль за значенням індексів при використанні масиву здійснює програміст.
3.4.6. Оголошення покажчика
Покажчик – це змінна, призначена для зберігання адреси об’єкту деякого типу. Покажчик на функцію містить адресу точки входу у функцію.
Синтаксис:
[<специфікація типу>]* <описувач>[,*<описувач>...];
Оголошення покажчика специфікує ім’я змінної – покажчик і тип об’єкту, на який може вказувати ця змінна. Специфікація типу може задавати базовий, перелічуваний, пустий, структурний тип чи тип об’єднання. Якщо специфікація типу опущена, то мається на увазі тип int.
Якщо <описувач> являє собою ідентифікатор (ім’я покажчика), то оголошується покажчик на значення специфікованого типу. Якщо ж <описувач> представляє більш складну конструкцію (див. розділ 3.3.1), то тип об’єкту, на який показує покажчик, визначається сукупністю частини описувача, що залишилася і специфікації типу.
Покажчик може показувати на значення базового, перелічуваного типу, структури, об’єднання, масиви, функції, покажчики.
Спеціальне застосування мають покажчики на тип void. Покажчик на void може показувати на об’єкт довільного типу. Однак, для виконання операції з покажчиком на void або над показуваним об’єктом, необхідно явно привести тип покажчика до типу, відмінного від void.
Покажчик на структуру, об’єднання чи перелічуваний тип може бути оголошений до того, як цей тип визначений, однак покажчик не повинен використовуватися до визначення цього типу. Покажчик при цьому оголошується шляхом використання тега (компілятору мови Сі не треба знати розмір об’єкту щоб розділити пам’ять під покажчик (розмір якої залежить від комп’ютера, компілятора, моделі пам’яті).
У стандартному файлі stdio.h визначена константа з іменем NULL. Вона призначена для ініціалізації покажчиків. Гарантується, що ніякий програмний об’єкт ніколи не буде мати адресу NULL.
Приклади: 1) char*message;
2) int*array[10];
3) int (*pointer) [10 ];
4) struct list * next, * previous;
struct list
{
char*name;
struct list * next;
struct list * previous;
}
3.5. Оголошення функції (прототип)
Старий метод:
[<специфікація_класу_пам’яті >][<специфікація_типу >]<описувач>
([<список_типів_ аргументів>];
Новий метод (прототип функції):
[<специфікація_класу_пам’яті>][<специфікація_типу>]<описувач>([<список аргументів>])
Оголошення функції специфікує ім’я функції, тип значення, що повертається і, можливо, типи її аргументів та їх число. Ці дані потрібні для перевірки коректності звертання до функції до того як вона визначена.
Якщо <описувач> - ідентифікатор (ім’я функції), то оголошується функція, для якої тип значення що повертається задається специфікацією типу. Якщо <описувач> більш складна конструкція (див. розділ 3.3.1) то частина <описувача>, що залишився в сукупності з <специфікацією_типу > задає тип значення, що повертається.
Функція не може повертати масив чи функцію, але може повертати вказівник на ці об’єкти.
<список_типів_аргументів> - список з одною чи більше імен типів розділених комами може містити ,… або . ... .
Метод оголошення прототипу функції:
список типів аргументів може містити також і ідентифікатори цих аргументів. Вони необов’язкові, їх область дії обмежується тільки прототипом, в якому вони визначені. Значить не обов’язково вони повинні співпадати з формальними параметрами у визначенні функції.
Основне призначення ідентифікаторів – підвищення читабельності програм.
3.6. Ініціалізація
Змінній в оголошенні може бути присвоєне початкове значення за допомогою ініціалізатора.
=<ініціалізатиор>
Можна ініціалізувати змінні довільного типу. Функції не ініціалізуються.
Для змінних оголошених на зовнішньому рівні ініціалізатор повинен являти собою константний вираз.
Змінні оголошенні на внутрішньому рівні можуть бути ініціалізовані не тільки константними виразами, а й виразами, що містять змінні і викликають функції.
3.6.1 Базові типи та покажчики
Синтаксис:
=<вираз>
При необхідності виконуються правила перетворення типів.
Приклади:
int x =10; int*p=& x;
3.6.2 Складені типи
Елементи об’єктів складених типів ініціалізуються тільки константними виразами.
Синтаксис:
={<список_ініціалізаторів>}
<список_ініціалізаторів> - послідовність ініціалізаторів розділених комами (береться у фігурні дужки). Кожен ініціалізатор у списку являє собою константний вираз, або в свою чергу, список ініціалізаторів. Значення константних виразів з кожного списку ініціалізаторів присвоюється елементам об’єкту складеного типу в порядку їх слідування.
Для ініціалізації об’єднання, список ініціалізаторів повинен містити один константний вираз. Ініціалізується перший елемент об’єднання.
Наявність списку ініціалізаторів дозволяє в оголошенні масиву не вказувати число елементів по його першій розмірності.
Якщо у списку ініціалізаторів менше елементів, ніж в об’єкті складеного типу, то решта елементів об’єкту неявно ініціалізуються нульовими значеннями.
Якщо ініціалізаторів більше ніж потрібно, то видається повідомлення про помилку. Ці правила застосовуються і до кожного вкладеного списку ініціалізаторів.
Приклади:
int p [4][3]={{1,1,1},{2,2,2},{3,3,3},{4,4,4}};
union
{ char m [2][3];
int i, j, k;
} y={{‘1’},{‘4’}};
Тільки перші елементи кожного рядка ініціалізуються значеннями, а решта нулями (неявно).
3.6.3. Рядкові ініціалізатори
Ініціалізація масиву типу char за допомогою символьного рядка:
char code []= ''abcd'';
char code [3]= ''abcd'';
Символьним рядком можна ініціалізувати також покажчик та тип char
char *ptr=''abcd'';
3.7 Оголошення типу
Існує два особливих види оголошення, в яких оголошується не змінна чи функція, а тип даних.
Перший вид дозволяє визначити тег та елементи структури, об’єднання чи перелічуваного типу. Після такого оголошення ім’я типу (тег) можна використовувати в оголошеннях змінних та функцій для посилання на цей тип.
Другий вид оголошення типу використовує ключове слово typedef. Це оголошення дозволяє присвоїти осмислені імена типам, що існують в мові, чи створюються користувачем.
Оголошення типу має також блочну область дії, як і оголошення змінної. Можливе також локальне переоголошення імені типу. Однак теги займають окремий простір імен, а ідентифікатори оголошені за допомогою typedef, розділяють простір імен зі змінними та функціями.
3.7.1 Оголошення тега, типу структури, об’єднання, перелічуваного типу.
Має таку ж структуру, як і оголошення змінних цих типів, однак опущений ініціалізатор змінної (в загальному випадку – описувач).
Іменем типу структури в цьому випадку є обов’язковий тег:
struct student
{
char name [20];
int id, group;
}
3.7.2 Оголошення typedef
Синтаксис:
typedef<специфікація типу ><описувач>[,<описувач>...];
(typedef замість класу пам’яті; ініціалізатор відсутній)
Оголошення typedef інтерпретується таким самим чином, як і оголошення змінної чи функції, однак індентифікатор, що входить до складу описувача специфікує не змінну чи функцію, а тип. Індентифікатор стає синонімом для оголошеного типу.
Приклади:
3.7.3 Абстрактні імена типів
Іноді виникає необхідність специфікувати деякий тип даних без присвоєння йому ідентифікатора і без оголошення якого небудь об’єкту.
Така конструкція, що визначає тип без імені, називається абстрактним іменем типу. Абстрактні імена типів використовуються у 3-х контекстах:
у списках типів аргументів при оголошенні функції;
в операції присвоєння типу;
в операції sigcof.
Синтаксис:
<специфікація_типу ><абстрактний_описувач>
Абстрактний описувач відрізняється від звичайного описувача тільки тим що не містить індентифікатора.
Для інтерпретації абстрактного описувача слід визначити у ньому місце індентифікатора, що мається на увазі.
Абстрактний описувач виду () не допустимий, бо невідомо, де мається на увазі індентифікатор:
а) якщо зліва – то функція;
б) якщо в дужках – то пустий тип.
Приклади:
long*
int (*)[s] покажчик на масив
int (*)(void)
4. Вирази
4.1. Вступ. Основні визначення та поняття
Вираз – це комбінація операндів та операцій що визначає порядок обчислень деякого значення. Операції визначають дії, що виконуються над операндами. Операнд, в найпростішому випадку, являється константою чи зміною. В загальному випадку кожен операнд виразу також являє собою вираз, що має деяке значення.
На відмінну від багатьох мов програмування високого рівня, в мові Сі присвоєння само являється виразом (значення виразу – результат, який присвоюється змінній, що задається лівим операндом). Окрім простого присвоєння в мові Сі існують складені операції присвоєння.
Результат обчислень виразу залежить від пріоритету операцій, а також від можливих побічних ефектів.
Пріоритет операцій визначає групування операндів у виразі і послідовність виконання операцій.
Побічним ефектом називається зміна значення якого-небудь операнда, викликана обчисленням іншого операнда.
Значення, що представляється операндом у виразі, має тип. Цей тип може бути в ряді випадків перетворений (явно чи неявно) в інший тип за деякими правилами. (Перетворення типів – розділ 4.7).
4.2 Операнди
Операндом виразу може бути константа, індентифікатор чи символьний рядок. Ці операнди можуть за допомогою так званих первинних операцій комбінуватися у первинні вирази – виклик функції, індексний вираз, вираз вибору елемента. Ці первинні вирази, в свою чергу, являються операндами виразу, який їх містить. Комбінація їх із іншими операціями призводить до утворення нових, більш складних виразів, що також являються операндами виразів, які їх містять і т.д.
Частина виразу взята у дужки, також розглядається, як операнд виразу.
Якщо всі операнди виразу являються константами, то він називається константним виразом.
Кожен операнд має тип. Тип операнда може бути явно приведений до іншого типу за допомогою операції приведення типу. Вираз приведення типу сам розглядається, як операнд виразу, що його містить.
4.2.1 Ідентифікатори
Ідентифікатори іменують змінні та функції. З кожним індентифікатором асоціюється тип, який задається при його оголошенні. Значення об’єкту, найменованого індентифікатором, залежить від типу наступним чином:
Ідентифікатори змінних цілого та плаваючого типів являють собою значення відповідного типу.
Ідентифікатор змінної перелічуваного типу являє собою значення однієї константи з відповідного цьому типу списку переліку. Тип цього значення – іnt.
Ідентифікатор структури чи об’єднання являє собою сукупність значень специфікованих цією структурою чи об’єднанням.
Ідентифікатор покажчика представляє адресу деякого об’єкту специфікованого типу.
Ідентифікатор масиву представляє масив, але якщо у виразі вимагається скалярна величина, то представляє адресу першого елемента цього масиву.
Тип ідентифікатора – покажчик на тип елементів масиву. Спорідненність між масивами і покажчиками являється суттєвою особливістю мови Сі. В багатьох випадках спосіб організації доступу до об’єкту – по покажчику чи як до елемента масиву – не має принципової різниці і визначається виключно обраним стилем програмування.
Існують однак деякі відмінності між масивами та покажчиками:
а) покажчик – одна комірка пам’яті для адреси об’єкта; масив займає сукупність комірок. Тільки у виразі масив представляється своєю адресою, яка еквівалентна покажчику.
б) адреса масиву являється сталою величиною, тому, на відміну від ідентифікатора покажчика, ідентифікатор масиву не може складати ліву частину операції присвоєння.
в) ідентифікатор функції представляє функцію, тобто адресу точки входу у функцію. Тип ідентифікатора – функція, що вертає значення специфікованого для неї типу. Однак, якщо у виразі потрібна скалярна величина, то типом ідентифікатора вважається покажчик на функцію.
Адреса функції не змінюється під час виконання програми, і, тому, не являється змінною величиною. Тому ідентифікатор функції не може складати ліву частину операції присвоєння.
4.2.2 Константи
Операнду – константі відповідає значення і тип константи, що його представляє:
символьна константа – int;
ціла – int, long, unsigned int, unsigned long;
плаваючою комою – double;
символьні рядки – тип масив символів.
4.2.3 Символьні рядки
Символьний рядок – послідовність символів у подвійних лапках. Ця послідовність представляється в пам’яті, як масив елементів типу char.
У виразі символьний рядок представляє адресу цього масиву, тобто адресу першого елемента рядка.
Символьний рядок не може складати ліву частину операції присвоєння.
4.2.4 Виклики функцій
Синтаксис:
<вираз>(<список_ виразів>)
<вираз> - адреса функції. В найпростішому випадку – ідентифікатор функції;
<список_ виразів> - містить вирази, розділені комами. Значення кожного з них відповідає фактичному аргументу функції.
Вираз виклику функції має тип – тип значення, що вертається функцією. Якщо оголошено тип значення, що вертається void , то і вираз виклику функції має тип void.
Якщо повернення з функції відбулося не в результаті виконання оператора return, який містить вираз, то значення функції не визначено.
4.2.5 Індексні вирази
Синтаксис:
<вираз1>[<вираз2>]
Значення індексного виразу розміщено за адресою, яка обчислюється, як сума значень <вираз 1> і <вираз 2>. <Вираз 1> повинен мати тип покажчика на деякий тип (наприклад, бути ідентифікатором масива), а <вираз 2> повинен мати цілий тип. Однак вимога синтаксису полягає тільки у тому, щоб один з виразів був покажчиком, а інший мав цілий тип. Порядок виразів не грає ролі.
Індексний вираз переважно використовується для доступу до елементів масиву, однак індексацію можна застосовувати до любого показчика.
Приклади:
а-масив, чи покажчик;
в-ціле.
Еквівалентні вирази:
a[b] *(a+b) *(b+a) b[a]
Індексний вираз обчислюється шляхом додавання цілого значення зі значенням покажчика (або адресою масиву) і наступним застосуванням операції непрямої адресації.
Пояснити на прикладі.
Перший елемент масиву має індекс 0.
Доступ до багатовимірного масиву.
Синтаксис:
<вираз1> [<вираз 2>] [<вираз 3>]…
Інтерпретація йде зліва направо. Спочатку обчислюється самий лівий індексний вираз - <вираз1> [<вираз 2>]. До отриманої адреси додається (за правилами додавання покажчика і цілого) <вираз 3> і т.д. <вираз 3> і наступні мають цілий тип. Потім операція непрямої адресації. Однак, якщо значення останього покажчика адресує тип масив, операція непрямої адресації не застосовується (3 та 4 приклади нижче).
Приклади:
int array [3][4][6];
int i, ip, (*ip p) [6];
i=array [0][ 0][1]; /*1 приклад*/
i=array [2][ 1][3]; /*2 приклад*/
а) Перший індекс 2 множиться на розмір двовимірного масиву (4х6), потім на розмір типу int і додається до значення покажчика arraу. Результат буде показувати на третій двовимірний масив.
б) Другий індекс 1 множиться на розмір 6 – елементного масиву типу int і додається до отриманої раніше адреси.
в) Три множиться на розмір int і додається до отриманої раніше адреси. Результуючий покажчик адресує четвертий елемет масива з шести елементів.
г) Непряма адресація.
iр=arraу [2][1]; /*3 приклад*/
Адресує другий шестиелементний масив.
iрр= arraу[]; /*4 приклад*/
Адресує третій динамічний масив.
4.2.6 Вибір елемента
Синтаксис:
<вираз>. <ідентифікатор>
<вираз> ( <ідентифікатор>
Вираз вибору елемента дозволяє отримати доступ до елемента структури чи об’єднання. Вираз має значення і тип обраного елемента.
Перша форма:
<вираз> - значення типа struct або union.
<ідентифікатор> - іменує елемент специфікованої структури чи об’єднання.
Друга форма:
<вираз> - покажчик на структуру чи об’єднання.
Запис <вираз>( <ідентифікатор> для випадку, коли вираз – покажчик, еквівалентний запису (*<вираз>). <ідентифікатор> однак більш наочний.
Приклади:
struct pair
{
int a, b;
struct pair *sp;
}item, list [10];
item.sp=( item; /*1 приклад*/
(item.sp)(а = 24; ( item.а=24; /*2 приклад*/
list [8].b=12; /*3 приклад*/

4.2.7 Операції та L – вирази
В залежності від операцій, що використовуються, вирази діляться на первинні, унарні, бінарні, тернарні, вирази присвоєння і вирази приведення типу.
а) Первинні вирази розглянуті в 4.2.4., 4.2.5., 4.2.6.
б) Унарні вирази
<унарна_операція> <операнд> (унарний плюс)
в) Бінарні вирази
<операнд 1 > <бінарна операція> <операнд 2> (додавання)
г) Тернарний вираз
<операнд 1 > ?<операнд 2> : <операнд 3> (умовна коперація)
д) Вирази присвоєння. Використовують унарні чи бінарні операції присвоєння.
Синтаксис виразів присвоєння:
Унарні операції присвоєння
< операнд>++ ++ <операнд >
< операнд>- - - - <операнд >
Бінарні операції присвоєння
< операнд 1>= <операнд 2>
< операнд 1> <складене _присвоєння><операнд 2>
є) Вирази приведення типу – застосовують операцію приведення типу для явного перетворення типу змінної скалярного типу (цілого, перелічуваного, плаваючого, пустого, покажчика)
(< абстрактне_ім’я_типу>) <операнд >
Операнди деяких операцій в мові Сі повинні являти собою так звані L – вирази (Lvalue-expressions). L – виразом являється вираз, який посилається на комірку пам’яті і тому має зміст в лівій частині бінарної операції присвоєння. Найпростіший приклад – ідентифікатор змінної.
Оскільки L – вираз посилається на комірку пам’яті, адреса цієї комірки може бути отримана за допомогою операції адресації ((). Виключення – адреса бітового поля, адреса змінної класа пам’яті register, хоча значення їм може бути присвоєно.
До L – виразів відносяться:
ідентифікатори змінних цілого, плаваючого, перелічуваного типів, покажчиків, структур та об’єднань;
індексні вирази, виключаючи ті з них, значення яких має тип масив;
вирази вибору елемента, якщо вибраний елемент сам являється одним з допустимих L – виразів;
вирази непрямої адресації, якщо тільки його значення не має тип масив чи функція;
L – вираз у дужках;
вираз приведення типу змінної, якщо розмір результуючого типу не перевищує розміру початкового типу.
Приклад:
сhar*p; int i; long n;
(long *)p= ( n; допустиме приведення типу.
(long)і= n; недопустиме приведення типу.
Перераховані L – вирази називаються L – виразами, що модифікуються. Існують L – вирази що не модифікуються; їх адреса може бути отримана, але використовуватися в лівій частині бінарної операції присвоєння вони не можуть.
Приклад: ідентифікатори масивів, функцій, змінні з модифікатором const.
4.2.8 Дужкові вирази
Довільний операнд може бути взятий у круглі дужки, наприклад (10+5)/5,
(10+5) - вираз, що являється лівим операндом операції ділення.
Хоча дужки впливають на те, яким шляхом групуються операнди у виразі, вони не гарантують певний порядок обчислення операндів для операцій, що мають властивості комутативності (мультиплікативні, адитивні, порозрядні операції).
Приклад:
(а+b)+c може обчислюватися як а+(b+c) і навіть як (а+с) +b.
4.2.9 Константні вирази
Константний вираз – вираз, результатом обчислення якого являється константа. Операндами константного виразу можуть бути цілі, символьні, плаваючі константи, константи перелічуваного типу, вирази приведення типу константного виразу, вирази з операцією sizeof, та інші константні вирази.
Деякі обмеження на використання операцій в константних виразах: заборонено використовувати операцію присвоєння, операцію послідовного обчислення. Існують інші обмеження. Константні вирази, що використовуються у директивах препроцесора мають додаткові обмеження.
4.3 Операції
Операції з одним операндом – унарні, з двома – бінарні, з трьома - тернарні.
Суттєвою властивістю будь-якої операції являється її асоціативність. Асоціативність – визначає порядок виконання у тому випадку, коли підряд застосовано декілька операцій одного виду. Асоціативність “зліва направо” означає, що першою буде виконуватися операція, знак якої записано лівіше інших.
Приклад:
b <<2<<2 ( (b<<2) <<2, а не b <<(2<<2)
Унарні операції мови Сі (асоціюються зправа наліво).
унарний мінус
+ унарний плюс
( обернений код
! логічне заперечення
( адресація
* значення за адресою
sizeof визначення розміру
Бінарні операції мови Сі (асоціюються зліва направо).
* / % мультиплікативні операції
+ - адитивні операції
<< >> операції зсуву
< > <= >= = = =!= операції відношення
( | ^ порозрядні операції
(( (( логічні операції
, операція послідовного обчислення
4.3.1 Перетворення по замовчуванню
Більшість операцій мови Сі виконують перетворення типів для приведення своїх операндів до загального типу, або для того, щоб розширити значення коротких по розміру типів до розміру, що використовується в машинних операціях. Перетворення, що залежать від конкретної операції та типу операнда (операндів), розглянемо пізніше.
Однак багато операцій виконують однакові перетворення цілих і плаваючих типів (перетворень по замовчуванню):
Всі операнди типу float перетворюються до типу double;
Якщо один операнд має тип double, то другий перетворюється до типу double;
Якщо один операнд має тип unsigned long, то другий перетворюється до типу unsigned long;
Якщо один операнд має тип long, то другий перетворюється до типу long;
Якщо один операнд має тип unsigned int, то другий перетворюється до типу unsigned int;
Всі операнди типів char (unsigned char) або short (unsigned short) перетворюються до типу int (unsigned int).
Інакше обидва операнди мають тип int.
4.3.2 Унарні операції
Унарний мінус (-)
Операція унарного мінуса виконує арифметичні заперечення свого операнда. Операнд повинен бути цілим або плаваючим значенням. Виконується перетворення операнда по замовченню. Тип результату співпадає з перетвореним типом операнда.
Унарний плюс (+)
Обернений код (()
Операція оберненого коду інвертує бітове представлення свого операнда. Операнд повинен мати цілий тип. Над операндом виконуються перетворення по замовчуванню. Результат має тип перетвореного операнда.
Логічне заперечення (!)
Операція логічного заперечення продукує значення 0, якщо операнд ІСТИНА і 1, якщо НЕПРАВДА.
Результат має тип int. Операнд повинен мати цілий, плаваючий тип або бути покажчиком.
Адресація (()
Операція адресації виробляє адресу свого операнда. Операнд може бути L- виразом, в тому числі таким, що не модифікується. Результат операції – покажчик на операнд. Тип результату – покажчик на тип операнда.
Значення за адресою (*)
Операція здійснює доступ до значення по покажчику. Операнд повинен мати тип покажчик. Як операнд може бути використаний ідентифікатор масиву; в цьому випадку він перетворюється на покажчик на тип елементів масиву.
Результат операції – значення на яке вказує операнд. Тип результату – тип, асоційований з цим покажчиком. Якщо покажчику перед операцією не було присвоєно ніякого значення, та результат невизначений.
int *pa, x;
int a[20];
double d;
pa=( a[5]; x(*(x.
x=*pa; d=*(double*)((x);
Операція sizeof
Операція sizeof визначає розмір пам’яті, якій відповідає об’єкту або типу.
sizeof <вираз> - істотне значення має не значення виразу, а його тип.
sizeof (<абстрактне_ім’я_типу>)
Результат операції – це розмір пам’яті у байтах.
Тип результату - unsigned int.
Зауваження:
а) в якості аргумента операнда недопустимий тип void.
б) результат застосування sizeof до ідентифікатора масива – розмір всього масива в байтах.
4.3.3 Мультиплікативні операції
*- множення, /- ділення, % - залишок від ділення.
Операнди %- цілі, *, / - цілі та плаваючі.
Для *, / - типи першого та другого операнда можуть відрізнятися (відбуваються перетворення по замовчуванню). Тип результату – тип операндів після перетворення.
В процесі виконання мультиплікативних операцій ситуація переповнення чи втрати значущості не контролюються. Якщо результат не може бути представлений типом операндів після перетворення, то інформація втрачається.
Множення (*)
Перший операнд множиться на другий.
Ділення (/)
Перший операнд ділиться на другий.
Якщо обидва операнди цілі і не діляться націло, то результат округлюється в сторону нуля. Ділення на 0 дає помилку під час виконання.
Залишок від ділення (%)
Результат – залишок від ділення першого операнда на другий. Знак результату співпадає зі знаком першого операнда.
4.3.4 Адитивні операції
+ - додавання, - - віднімання.
Операнди – цілі чи плаваючі значення. В деяких випадках адресні адитивні операції можуть виконуватися над адресними значеннями. Над операндами відбуваються перетворення по замовчуванню. Тип результату – тип операндів після перетворення. Ситуація переповнення чи втрати значущості не контролюється. Якщо результат не може бути представлений типом операндів після перетворення, то інформація втрачається.
Додавання (+)
Додавання – додає два своїх операнда. Операнди – цілий або плаваючий тип.
Типи операндів можуть відрізнятися.
Один з операндів може бути пожчиком. Тоді другий, повинен бути цілим значенням. Тип результату покажчик та тип той же, що й доданка. (Пояснити процес додавання в цьому випадку).
Віднімання (-)
Віднімання – віднімає другий операнд від першого. Операнди – цілий чи плаваючий. Типи операндів можуть відрізнятися. Допускається віднімання цілого від покажчика та віднімання покажчиків. В першому випадку тип результату – покажчик на тип той же, що і для зменшуваного.
В другому – знакове ціле.
Адресна арифметика – коректність застосування – пояснити (у масивів елементи йдуть підряд, а у інших об’єктів не завжди; проблеми з моделями пам’яті).
int i =4, j;
flout * [10];
flout * px;
px=(*x[4]+i; /*приклад 1*/ - адреса 9-го елемента масиву.
j=(x[i]- (x[i-2]; /*приклад 2*/ i=2.
4.3.5 Операції зсуву
Операції зсуву зсувають свій перший операнд вліво (<<) або вправо (>>) на число розрядів машинного слова, що задане другим операндом.
Обидва операнди – цілі. Використовуємо перетворення по замовчуванню (СП МSC над обома операндами спільно, а в СП ТС – незалежно над кожним операндом).
int b;
unsigned long u; b<<u (в СП МSC в ( unsigned long)
Тип результату: СП ТС – тип лівого операнда після перетворення.
СП МSC – єдиний тип перетворення.
При зсуві вліво біти, що звільняються заповнюються 0. При зсуві вправо: для unsigned – 0; для знакових – знаковим бітом.
Якщо другий операнд <0, то результат невизначений. Ситуація втрати значущості не контролюється. Якщо результат зсуву не може бути представлений типом першого операнда після перетворення, то інформація втрачається.
4.3.6 Операції відношення
Порівнюють перший операнд з другим і дають значення 1 (істина) або 0 (неістина). Результат має тип int.
<, >, <=, >=, = =, != (перший операнд менший ніж другий і т.д.)
Операнди можуть мати цілий, плаваючий тип, або бути покажчиками. Типи першого і другого операндів можуть відрізнятися. Виконуються перетворення по замовчуванню.
Операція перевірки рівності чи нерівності покажчиків вказує, чи обидва покажчики вказують на один і той же об’єкт.
Покажчик можна перевірити на рівність чи нерівність константі NULL.
Не рекомендується перевіряти на рівність плаваючі значення, оскільки 1.0/3.0х3.0 не буде рівне 1.0.
4.3.7 Порозрядні операції
(, !, ^. Операнди повинні мати цілий тип. Біт знака приймає участь в операції. Виконує перетворення по замовчуванню. Тип результата визначається типом операндів після перетворення.
Таблиця значень для порозрядних операцій
х 0011
у 0101
х/у 0111
х(у 0001
х^у 0110
4.3.8 Логічні операції
((, ((; Операнди логічних операцій повинні мати цілий, плаваючий тип або бути покажчиками. Типи операндів можуть відрізнятися один від одного. Спочатку завжди обчислюється перший операнд, якщо його значення достатньо для визначення результата операції, то другий операнд не обчислюється.
Логічні операції не виконують перетворення по замовчуванню. Замість цього вони обчислюють операнди та порівнюють їх з нулем. Результат логічної операції 0 (неістина), 1 (істина).Тип результату int.
Логічне І ((()
Виробляє 1, якщо обидва операнди ненульові, інакше 0.
Якщо значення першого операнда рівне 0, то другий операнд не обчислюється.
Логічне АБО ((()
Виробляє 0, якщо обидва операнди нульові, інакше 1. Якщо перший операнд не рівний нулю, то значення другого операнда не обчислюється.
4.3.9 Операція послідовного обчислення
Послідовно обчислює два своїх операнда: спочатку перший, потім другий. Обидва операнди являються виразами.
Синтаксис:
<вираз 1>,<вираз 2>
Результат операції має значення і тип другого операнда. Обмеження на типи операндів (типи результатів виразів) не накладаються. Перетворення типів не виконується.
Операція послідовного обчислення звичайно застосовується для обчислення декількох виразів в ситуаціях, де по синтаксису допускається тільки один вираз.
Приклади:
for (1=j=1; i+j<20; i+=i, j--)
Три аргументи - func 1 (x, y+2, z);
Два аргументи - func 2 ((x--, y+2), z);

4.3.10 Умовна операція
Синтаксис:
<операнд 1>?<операнд 2>:<операнд 3>
Вираз <операнд 1> обчислюється і порівнюється з нулем. (Вираз може мати цілий, плаваючий тип або бути покажчиком). Якщо <операнд 1> - ненульове значення, то обчислюється <операнд 2> і результатом умовної операції буде його значення. Якщо <операнд 2> рівний нулю, то обчислюється <операнд 3> і результатом являється його значення. В будь-якому випадку обчислюється тільки один з операндів: <операнд 2> або <операнд 3>.
Тип результату залежить від типів другого і третього операндів:
2 і 3 операнди мають цілий або плаваючий тип – виконуються перетворення по замовчуванню. Тип результату – тип операндів після перетворення.
2 і 3 операнди - це структури, об'єднання чи покажчики одного й того ж самого типу. Тип результату тоді такий же самий.
або 2 або 3 операнд має тип void (наприклад виклик функції, що вертає void), то другий операнд також повинен мати тип void, і результат має тип void.
або 2 або 3 операнд – покажчик на якийсь тип, а другий інший покажчик на void то результат має тип покажчик на void.
або 2 або 3 операнд – покажчик, то інший може бути константним виразом зі значенням 0. Тип результату – покажчик.
j=(i< 0)?(-i):(i);
j=(i< 0)?(-1):(1);
4.4 Операції присвоєння
Операція Дія
+ + унарний інкремент
- - унарний декремент
= просте присвоєння
*= множення з присвоєнням
/= <<=
%= >>=
+ = >=
- = |=
^=
При присвоєнні тип правого операнда перетворюється до типу лівого. Лівий операнд (або єдиний для унарної операції) повинен бути L – виразом, що модифікується. (Нагадати: операція присвоєння в мові Сі є виразом і виробляє значення, яке може бути надалі використане в обчисленні виразу.)
4.4.1 Операції інкременту та декременту
+ + - -, операнд – цілий, плаваючий тип або покажчик. Операнди цілого чи плаваючого типу збільшуються або зменшуються на цілу одиницю. Перетворення по замовчуванню не виконується.
Тип результату відповідає типу операнда. Операнд типу покажчик інкрементується або декрементується на розмір об’єкту, який він адресує, за правилами адресної арифметики. Інкрементований покажчик адресує наступний елемент даного типу, а декрементований покажчик – попередній.
Префіксна форма, постфіксна форма.
дія, а потім застосування застосування, а потім дія (відповідно).
Результат операції: або нове або старе значення операнда.
if(pog++> 0) char *s; *d;
*p++=*q++; while (*s++=*d++);
4.4.2 Просте присвоєння
=, Результат – це присвоєне значення. Тип – тип лівого операнда.
4.4.3 Складене присвоєння
<вираз 1>+=<вираз 2> (спочатку виконується додавання, а потім присвоєння, вираз 1 бчислюється один раз)
<вираз 1>=<вираз 1>+<вираз 2>(вираз 1 обчислюється два рази)
Наприклад:
*str 1. str 2. ptr+=5 краще і виконується швидше, ніж
*str 1. str 2. ptr=*str 1. str 2. ptr+5.
Кожна операція складеного присвоєння виконує перетворення, що визначаються бінарною операцією, що входить в її склад, і відповідно обмежує типи своїх операндів. Результат – значення, присвоєне лівому операнду. Тип – тип лівого операнда.