Поняття виразу, операнда, операції 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Поняття виразу, операнда, операції



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

Операндами виразів можуть бути константи, змінні, первинні вирази – елементарні під вирази даного виразу. Операнди більшості операцій мови С++ мають бути скалярними даними, тобто вони можуть мати арифметичний, переліковий або вказівниковий тип.

В мові С++ великий набір вбудованих операцій, що дозволяє створювати компактні програми. Операції можна класифікувати за різними ознаками. Зокрема, за кількістю операндів, що вступають в операцію, виділяють унарні операції – застосовуються до одного операнда; бінарні – в операцію вступають два операнди; тернарні – в операцію вступають три операнди (існує лише одна така операція – умовна операція).

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

За старшинством (пріоритетом) операції поділяють на 16 рівнів, табл. 4.1. Найвищий пріоритет мають так звані первинні операції з пріоритетом 16, найнижчий – операція послідовних обчислень «кома».

 

Таблиця 4.1. Операції мови програмування С++

Пріо-ритет Знак Зміст операції Тип Асоціатив- ність

16

() Звертання до функції

Первинні

Зліва

направо

[ ] Виділення елемента масиву через індекс
. Виділення елемента структури
-> Виділення елемента структури через вказівник

15

++ Постфіксний інкремент (збільшення на 1)

Присвоєння

-

-- Постфіксний декремент (зменшення на 1)

14

- Зміна знака

Різнотипні

унарні

Справа

наліво

++ Префіксний інкремент (збільшення на 1)
-- Префіксний декремент (зменшення на 1)
! Логічне заперечення
~ Побітове заперечення
& Визначення адреси
* Звертання через вказівник (адресу)
(тип) Перетворення до заданого типу
sizeof Визначення розміру операнда вв байтах

13

* Множення

Арифме-тичні

Зліва

направо

/ Ділення
% Остача від ділення

12

+ Додавання
- Віднімання

11

<< Зсування вліво

Зсування

(побітові)

>> Зсування вправо

10

< Менше

Порівняння

(відношен-ня)

<= Не більше
> Більше
>= Не менше

9

== Дорівнює
!= Не дорівнює
8 & Побітове AND

Поразрядні

(побітові)

7 ^ Побітове XOR
6 | Побітове OR
5 && Логічне І

Логічні

4 || Логічне АБО

Продовження табл. 4.1

3 ?: Вибір операнда за умовою Умовна

Справа

наліво

2

= Звичайне присвоєння

Присвоєння

*= Множення з присвоєнням
/= Ділення з присвоєнням
%= Остача від ділення з присвоєнням
+= Додавання з присвоєнням
-= Віднімання з присвоєнням
>>= Зсування вправо з присвоєнням
<<= Зсування вліво з присвоєнням
&= Побітове AND з присвоєнням
|= Побітове XOR з присвоєнням
^= Побітове OR з присвоєнням
1 , Послідовні обчислення Кома Зліва направо

 

Порядок виконання операцій

Порядок обчислення значення виразу базується на таких правилах:

1) з двох сусідніх операцій першою буде виконана та, пріоритет якої вищий;

2) операції однакового пріоритету виконуються зліва направо або з права наліво залежно від асоціативності, встановленої для даної групи операцій (табл. 4.1);

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

Стандарт мови програмування С++ не встановлює порядку звертання до операндів в процесі виконання операції. Тобто, у виразі

 

w = (a + b) * (a - b);

 

операцію множення гарантовано буде виконано перед операцією присвоєння і після обчислення значень виразів у дужках. Але який з двох операндів – виразів (a+b) чи (a-b) буде обчислений першим – не визначено. В деяких випадках значення виразу залежить від порядку звертання до операторів. Наприклад

 

d = c + twice(&c);

 

Функція twice вдвічі збільшує значення змінної, адреса якої передана їй в якості параметра, і повертає нове значення. Нехай початкове значення змінної с дорівнює 5. Тоді значення виразу, що буде присвоєний змінній d, може дорівнювати 5+10=15, якщо першим буде вибраний лівий операнд, а потім – правий; або 10+10=20, якщо спочатку обчислюється правий операнд, тобто відбувається виклик функції, яка змінює значення с. Необхідно уникати виразів, результати обчислення яких можуть бути неоднозначними.

Арифметичні операції

До арифметичних належать такі операції (згідно з порядком старшинства операції):

1) -      (зміна знака операнда, унарна операція);

2) * / % (множення, ділення, остача від ділення, бінарні операції);

3) + - (додавання, віднімання, бінарні операції).

Операції * / + - виконуються над операндами всіх числових типів (цілих і дійсних), операція % потребує двох цілочислових операндів. Результат виконання всіх арифметичних операцій над двома операндами цілого типу завжди є цілим.

 

#include <iostream>

#include <cmath>

using namespace std;

int main(){

int a = 7, b = 3;  // 7 = 3 * 2 + 1

cout << a / b << endl; // 2

cout << a % b << endl; // 1

cout << (double)a / b << endl; // 2.3333

}

 

Порозрядні операції

Порозрядні операції (їх ще називають побітовими чи просто бітовими) виконуються тільки над операндами цілих типів. До них належать (згідно з порядком старшинства операції):

1) ~ (побітова інверсія, унарна операція);

2) <<        (зсування вліво), >> (всування вправо);

3) & (побітове AND);

4) ^ (побітове XOR);

5) | (побітове OR).

Використання порозрядних операцій дає змогу оперувати окремими бітами даних, перевіряти або змінювати їх значення, що наближає програмування мовою С++ до можливостей асемблера.

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

 

Таблиця 4.2. Таблиця істинності порозрядних операцій

Розряди

Результат операції

ai bi AND XOR OR
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 0 1

 

Операцію & називають накладанням маски, оскільки вона дає змогу виділити потрібні розряди цілочислового операнда. Наприклад, необхідно визначити значення першого біту числа. В масці в першому біті записуємо одиницю, в інших бітах – нуль. При виконанні операції & значення першого біту буде збережено, значення всіх інших – замінені на нуль.

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

Операції << i >> зсувають усі розряди цілочислового операнда, заданого зліва від знака операції, на кількість бітів, вказану справа від знака операції.

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

Проілюструємо використання побітових операцій такою програмою:

 

#include <iostream>

using namespace std;

 

void print_bin(unsigned char x) {

unsigned char mask = 1 << 7;

while (mask) {

    cout << (x & mask? 1: 0);

    mask >>= 1;

}

cout << endl;

}

 

int main(){

unsigned char a = 240;

unsigned char b = 170;

cout << "a "; print_bin(a);  // 11110000

cout << "b "; print_bin(b);  // 10101010

cout << "a & b "; print_bin(a & b); // 10100000

cout << "a | b "; print_bin(a | b); // 11111010

cout << "a ^ b "; print_bin(a ^ b); // 01011010

cout << "~a "; print_bin(~a); // 00001111

}

 

Операції порівняння

Операції порівняння (ще їх називають операціями відношення) є бінарними. Результатом виконання операцій є величина логічного типу – true або false. До операцій порівняння відносять:

1) > більше;

2) >= не менше;

3) < менше;

4) <= не більше;

5) == дорівнює;

6)!= не дорівнює.

Поширеною помилкою є використання знаку присвоєння = замість знака рівності ==. Оскільки присвоєння це також операція, що повертає присвоєне значення, компілятор може не фіксувати помилку в таких виразах, але часто видає попередження.

Логічні операції

В мові програмування С++ застосовуються три логічні операції:

1)!      логічне заперечення, унарна операція;

2) && логічне І, бінарна операція;

3) ||     логічне АБО, бінарна операція.

Операндами логічних операцій є логічні дані – істина (true) і хибність (false). Результатом логічної операції є величина логічного типу. Операндами також можуть бути числові дані: будь яке не нульове значення – це істина, нуль – хибність. Цей підхід використовується в мові програмування С, в якій немає логічного типу даних bool.

Операція логічного заперечення змінює логічне значення на протилежне. Тобто,

 

#include <iostream>

using namespace std;

int main(){

bool a = true;

cout << a << endl; // 1

cout <<!a << endl; // 0

}

 

Результат бінарної операції && буде істинним (не буде дорівнювати нулю), тільки в тому разі, коли обидва операнди є істинними (не дорівнюють нулю). Результат виконання операції || буде істинним, коли істинним є хоча б один з операндів.

Логічні вирази в С++ не обов’язково мають бути обчислені повністю. Як тільки значення виразу стає однозначним, подальші обчислення припиняються. При цьому, лівий операнд логічної операції обчислюється першим, а правий – другим. Це дає можливість записувати вирази, в яких одразу виконується зміна даних і перевірка. В деяких випадках це може призводити до некоректної роботи програми. Наприклад:

 

1 #include <iostream>

2 using namespace std;

3 int main(){

4 int a1 = 0, b1 = 1, c1 = 2;

5 int a2 = 0, b2 = 1, c2 = 2;

6 bool r;

7 r = b1 < c1 && ++a1 > 0;    // r = true

8 cout << "a1 = " << a1 << endl; // a = 1

9 r = b2 > c2 && ++a2 > 0;    // r = false

10 cout << "a2 = " << a2 << endl; // a = 0

11 }

 

В програмі обчислення значення змінної r виконується в рядках 7 і 9. В обох випадках використовують логічну операцію І. При виконанні операції І першим буде обчислене значення лівого операнда. Якщо це false, то незалежно від значення правого операнда результат виконання операції буде false, і вираз справа від знака операції І обчислений не буде. В прикладі в рядку 7 обчислюються вирази і зліва, і заправа від знака операції І, в рядку 9 – лише зліва. Таким чином, незважаючи на те, що пріоритет операції префіксного інкременту більший пріоритетів логічних операцій і операцій порівняння, в рядку 9 змінна а не буде збільшена на одиницю.

Операції присвоєння

Операції присвоєння можна поділити на 2 групи:

1) унарні операції:

a. ++     (постфіксний і префіксний інкремент, збільшення на одиницю),

b. --       (постфіксний і префіксний інкремент, зменшення на одиницю);

2) бінарні операції:

a. =       (звичайне присвоєння),

b. *=     (множення з присвоєнням),

c. /=      (ділення з присвоєнням),

d. %=    (остача від ділення з присвоєнням),

e. +=     (додавання з присвоєнням),

f. -=      (віднімання з присвоєнням),

g. &=    (побітове І з присвоєнням),

h. ^=     (побітове виключне І з присвоєнням),

i. |=      (побітове АБО з присвоєнням),

j. <<= (зсування вліво з присвоєнням),

k. >>= (зсування вправо з присвоєнням).

На відміну від інших операцій, операції присвоєння змінюють значення свого операнда: для бінарних операцій лівий операнд набуває значення виразу, записаного справа від знака присвоєння, для унарних операцій – змінюється значення єдиного операнда даної операції. Тому операнд, якому присвоюється значення, повинен бути так званим l-операндом (l-value, left side value) – змінною розадресованим вказівником, тобто він має задавати адресу оперативної пам'яті, куди буде записане значення, яке присвоюється.

Результатом операції присвоєння є значення, яке набуває змінна (l-операнд) після присвоєння. Це значення можна використовувати як операнд у наступних операціях, для яких присвоєння є підвиразом. Операції присвоювання виконуються справа наліво, що дозволяє записати вираз, який складається з декількох присвоєнь (рядок 5 і 7).

 

1 #include <iostream>

2 using namespace std;

3 int main(){

4 int a, b, c;

5 a = b = c = 123;

6 cout << a << endl; // 123

7 a = b = c + 321;

8 cout << a << endl; // 444

9 }

 

Бінарні присвоєння стоять у кінці списку пріоритетів, тому іноді підвираз присвоювання слід охоплювати дужками:

 

#include <iostream>

using namespace std;

int main(){

int a, b = 1, c = 2;

bool r;

r = a = b + c < 2; // 0, a = 3 < 0, a = 0

cout << a << endl;

r = (a = b + c) < 2; // 3

cout << a << endl;

}

 

Комбіновані присвоєння є окремим випадком звичайних присвоювань. Вираз

 

операнд1 операція= операнд2;

 

є скороченим записом операції присвоєння:

 

операнд1 = операнд1 операція операнд2;

 

Операція виключне АБО має таку особливість: (a ^ b) ^ b = a. Тобто, якщо виконати операцію 2 рази з однаковим другим операндом, ми отримаємо значення першого операнда. Це дозволяє виконувати обмін двох цілочислових змінних значеннями.

 

#include <iostream>

using namespace std;

int main(){

int a = 123, b = 321;

a ^= b ^= a ^= b;

cout << "a = " << a << endl; // 321

cout << "b = " << b << endl; // 123

}

 

В програмах на С++ широко застосовують унарні операції присвоєння ++ і --. Перша з них називається інкрементом, вона збільшує значення операнда на одиницю. Друга – декрементом, зменшує значення операнда на одиницю. Можна застосовувати дві форми запису операцій інкремента і декремента: префіксну, коли знак ++/-- записується перед операндом, і постфіксну – коли знак операції вказується після операнда.

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

 

#include <iostream>

using namespace std;

int main(){

int a = 0, b = 0;

a++; ++a; a += 1; a = a + 1; // Збільшення на 1

b--; --b; b -= 1; b = b - 1; // Зменшення на 1

cout << "a = " << a << endl;

cout << "b = " << b << endl;

}

 

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

 

#include <iostream>

using namespace std;

int main(){

int a = 3, b = 3, ta, tb;

ta = ++a + 1;

tb = b++ + 1;

cout << "ta = " << ta << endl; // 5

cout << "tb = " << tb << endl; // 4

}

 

Умовна операція

Цю операцію також називають операцією вибору операнда. Вона виконується над трьома операндами (єдина тернарна операція С++) і записується так:

 

вираз_1? вираз_2: вираз_3

 

Якщо значення виразу 1 істинне (не дорівнює нулю), то результатом умовної операції є значення виразу 2. Якщо значення виразу 1 хибне (дорівнює нулю), то результатом умовної операції є значення виразу 3. У багатьох випадках замість умовного оператора if можна використовувати умовну операцію, що дозволяє скоротити програму та зробити її більш наочною.

 

#include <iostream>

using namespace std;

int main(){

int a = -1, b = 2, t;

t = a > b? a: b;

cout << "max(a,b) = " << t << endl; // 2

t = a > 0? a: -a;

cout << "abs(a) = " << t << endl;    // 1

}

 



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 167; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.190.160.221 (0.103 с.)