Директиви умовної компіляції 


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



ЗНАЕТЕ ЛИ ВЫ?

Директиви умовної компіляції



Для організації умовної компіляції використовують директиви препроцесора #if, #else, #elif, #endif, #ifdef, #ifndef а також операцію defined. Ці директиви призначені для вибіркової компіляції окремих частин програми. Вони дають змогу опустити компіляцію тих фрагментів програми, які не відповідають заданим умовам. Умовну компіляцію використовують при налагодженні програм і в випадках, коли існує декілька спеціальних версій загальної програми.

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

 

#if константний_вираз

фрагмент_програми

#endif

 

Повна форма директиви #if:

 

#if константний_вираз

фрагмент_програми_1

#else

фрагмент_програми_2

#endif

 

Константний вираз директиви #if, який задає умову компіляції, може складатися з констант або ідентифікаторів макропідстановок. У разі використання короткої форми запису директиви умовної компіляції, фрагмент програми між #if і #endif буде компілюватися тільки за умови, що значення константного виразу істинне (відмінне від нуля). У разі використання повної форми запису цієї директиви, буде компілюватися або фрагмент програми 1 (якщо значення виразу істинне), або фрагмент програми 2 (якщо значення виразу хибне). Кінець фрагменту програми, який підлягає умовній компіляції, задає директива #endif. В наступному прикладі до програми будуть підключатися різні заголовні файли, залежно від обраної мови:

 

#define UKR 1

#define ENG 2

#define LANG UKR

#if LANG == UKR

#include "ukr.h"

#else

#include "eng.h"

#endif

 

Директива #elif є спрощеним варіантом конструкції #else - #if. Синтаксис її такий самий, як і директиви #if:

 

#elif константний_вираз

фрагмент_програми

 

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

 

#if константний_вираз_1

фрагмент_програми_1

#elif константний_вираз_2

фрагмент_програми_2

#elif константний_вираз_k

фрагмент_програми_k

#else

альтернативний_фрагмент_програми

#endif

 

В цьому випадку першим перевіряється константний вираз 1. Якщо він хибний, то перевіряється вираз 2 і так далі, доки не буде знайдено істинний вираз. Якщо такий вираз знайдено, то відповідний фрагмент програми передається на компіляцію, перевірка умов завершується. Якщо всі вирази хибні, то компілюватись буде фрагмент програми, що відповідає варіанту #else, за умови, що він є в програмі. Таким чином, на компіляцію буде передано тільки один, або не передано жодного, з усіх фрагментів програми, що підлягають умовній компіляції.

 

#define UKR 1

#define ENG 2

#define RUS 3

#define LANG ENG

#if LANG == UKR

#include "ukr.h"

#elif LANG == ENG

#include "eng.h"

#elif LANG == RUS

#include "rus.h"

#else

#include "ukr.h"

#endif

 

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

Директиви #ifdef, #ifndef

Ще одним способом організації умовної компіляції є використання директив #ifdef (if defined – за умови визначеності) і #ifndef (if not defined – за умови невизначеності). Синтаксис їх однаковий:

 

#ifdef ім’я_макросу

фрагмент_програми

#endif

 

#ifndef ім’я_макросу

фрагмент_програми

#endif

 

Обидві директиви перевіряють, чи був макрос, ім’я якого задається в цій директиві, попередньо визначений директивою #define. При цьому не вимагається, щоб макрос мав повне визначення, достатньо оголошення

 

#define ім’я_макросу

 

Фрагмент програми, обмежений директивами #ifdef … #ifndef буде компілюватись за умови, що ім’я макросу попередньо визначене. Дія директиви #ifndef протилежна – фрагмент програми передається на компіляцію, якщо заданий макрос не визначений.

Умовну компіляцію можна використовувати для налагодження програм. Зокрема, в текст програм можна включити ряд контрольних перевірок і повідомлень, що допоможуть відстежити процес виконання програми. Наприклад:

 

#include <iostream>

using namespace std;

#define DEBUG

int main() {

int a = 123;

#ifdef DEBUG

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

#endif

}

 

Таких контрольних точок можна створити в програмі декілька. Коли від лагодження програми завершене, достатньо закоментувати директиву #define DEBUG або використати директиву #undef DEBUG.

Директиви #ifdef і #ifndef використовують в заголовних файлах для захисту програми від повторних включень заголовних файлів, які можуть виникнути через вкладення директив #include. Оголосимо структуру для збереження інформації про студентів в окремому файлі:

 

// student.h

#ifndef STUDENT_H

#define STUDENT_H

struct student {

int id;

int rating;

student * next;

};

#endif

 

#include <iostream>

#include "student.h"

using namespace std;

int main() {

struct student * p;

 

У разі повторного підключення файлу student.h макрос STUDENT_H вже буде визначеним і директива #ifndef пропустить препроцесування вмісту файлу.

Перевірити, чи ім’я заданого макросу визначене, можна також за допомогою операції defined, яка застосовується в виразах умови директив #if i #elif і має такий синтаксис:

 

defined ім’я_макросу

 

Якщо даний макрос був попередньо визначений, то результат операції буде істинний. До результатів цієї операції можна застосовувати логічні операції!, &&, ||. Попередній приклад можна записати так:

 

#if!defined STUDENT_H

#define STUDENT_H

struct student {

int id;

int rating;

student * next;

};

#endif

 

За допомогою цієї операції можна перевіряти визначеність декількох макросів:

 

#if defined A && defined B

#endif

 

Функції

Структура функції

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

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

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

Функція описується синтаксичною конструкцією такого виду:

 

тип_значення_функції ім’я_функції (оголошення_параметрів) {

тіло_функції

}

 

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

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

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

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

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

Функція завершує свою роботу, коли виконані всі оператори її тіла та досягнуто кінця функції або коли зустрінеться оператор return. Якщо тип значення функції – це void, то вона не повертає значення і оператор return для неї не обов’язковий. Але при необхідності його можна використовувати для переривання роботи функції. Наприклад:

 

#include <iostream>

using namespace std;

void PrintSqrt(double x) {

if (x < 0) {

     cout << "x < 0" << endl;

     return;

}

cout << sqrt(x) << endl;

}

int main() {

PrintSqrt(-1.);

PrintSqrt(4);

}

 

В цьому прикладі при виконання умови x < 0 на екран буде виведене відповідне повідомлення, після цього виконання функції буде завершене, управляння передане в точку її виклику.

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

 

#include <iostream>

using namespace std;

int sum(int a, int b) {

int t;

t = a + b;

return t;

}

int max(int a, int b) {

if (a > b)

     return a;

return b;

}

int main() {

int x = 3, y = 4;

cout << sum(x, y) << endl;

cout << max(2, 3) << endl;

}

 



Поделиться:


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

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