Лекции по структури от данни и програмиране



страница4/4
Дата25.07.2016
Размер0.95 Mb.
#6569
ТипЛекции
1   2   3   4

препроцесорът е програма за подготовка за процеса на компилация; тази възможност е характерна за езиците за системно програмиране; обикновено в средите за програмиране ние извикваме компилатора, а той препроцесора;
препроцесорът заменя всички коментари с интервали; те не влияят на ефективността на програмата, тъй като компилатора ги пропуска;

в C и C++ ние можем да задаваме специални инструкции към препроцесора; това става с помощта на така наречените директиви на препроцесора; общият вид на една директива е следния:

#ключова_дума вид_на_заместването

ключовата дума се записва с малки букви, а вида на заместването определя какви промени ще се извършват; в края на директивата не се поставя ‘;’; директивите се записват самостоятелно на един ред на произволно място в програмата; възможно е директивите да се записват на няколко реда, но в края на всеки ред (с изключение на последния) трябва да поставим символа ‘\’;

например:

#ключова_дума\

вид_на_заместването

директивите не са част от C и C++ - те задават определени действия, които се извършват върху първичния файл в ASCII код;


макроопределения се извършват с помощта на директивата define; синтаксисът е следния:

#define име_на_макрос низ

името е произволен идентификатор; след като срещне директивата define, препроцесорът замества всяко по-нататъчно срещане на името на макроса с указания низ; този процес наричаме разширяване на макроса; прието е имената на макросите да се записват с главни букви за да се отличават от останалите елементи в програмата; примери:

#define PI 3.14159

#define LIMIT 100

int masiv[LIMIT];

for (int i = 0; i < LIMIT; i++) { masiv[i] = …; }
възможно е низът в директивата define сам по себе си да съдържа макрос; например:

#define EXPR (PI*r*r)

това е възможно, тъй като след като извърши разширяването на целия текст, препроцесорът преглежда наново файла дали не са възможни още разширявания;

разширяването на EXPR в програмата ще се извършва на две стъпки: EXPR  (PI*r*r)  (3.14159*r*r);

ако името на макроса се среща в символна или низова константа, то при изпълнение на define препроцесорът не разширява това срещане;

едно и също име на макрос може да бъде дефинирано многократно в програмата; новото определение отменя действието на последното въведено определение;

действието на define може да бъде отменено с помощта на директивата undef със следния синтаксис:

#undef име_на_макрос

името на макроса определя макроса, който искаме да отменим; след тази директива този макрос престава да се разширява от препроцесора; пример:

#define GLOB 10

#define GLOB 500



#undef GLOB

между двете директиви define GLOB ще се замества с 10, а след втората директива define GLOB ще се замества с 500 до директивата undef, а след нея макросът GLOB вече не е дефиниран;


възможно е да се дефинира макрос без да се задава низ; например:

#define TEST

такива макроси се наричат празни и те се използват при условна компилация; празните макроси не се разширяват, т.е. ако в програмата препроцесорът срещне TEST той няма да го разшири и компилаторът ще даде синтактична грешка;
при разработване на програми много често възниква необходимостта от обединяването на няколко първични файла в един; това се постига с директивата include със следния синтаксис:

#include “име_на_файл”

#include <име_на_файл>

когато препроцесорът срещне директива include, той открива посочения първичен файл (в ASCII код) и след това на мястото на директивата записва текста на файла; самият файл може също да съдържа директиви на препроцесора – те ще бъдат обработени при следващото разширение;

разликата в синтаксиса на include е в начина по който се търси файла; ако файлът е записан с “”, той се търси първо в текущата директория и след това в include-директорията, т.е. директорията със стандартните файлове за включване; ако файлът е записан с <>, той директно се търси в include-директорията;
34. Макроопределения с аргументи.
макроопределения с аргументи се дефинират по следния начин:

#define име_на_макрос(списък_от_формални_аргументи) низ

между името на макроса и отварящата скоба на списъка от аргументи не трябва да има интервали – ако има интервал препроцесорът ще интепретира директивата като макроопределение без аргументи; имената на формалните аргументи са валидни само за дефиницията и те могат да съвпадат с други идентификатори в програмата без това да води до грешка; когато използваме името на макроса в програмния текст, фактическите аргументи могат да бъдат произволна последователност от символи; когато препроцесорът срещне в програмата макрос с аргументи, той го обработва по следния начин:


  1. в низа на директивата define формалните аргументи се заместват с фактическите аргументи;

  2. името на макроса, следвано от списъка с фактическите аргументи се замества с променения в 1. низ;

примери:

#define PI 3.14159

#define CIRCLE(r) (PI*(r)*(r))

double x, y, z;



z = CIRCLE (x);


заместването се извършва на две стъпки:

CIRCLE (x)  (PI*(x)*(x))  (3.14159*(x)*(x));


скобите, които заграждат формалния аргумент r са необходими;

например, ако запишем CIRCLE (x+1) и те липсваха, препроцесорът би извършил следното заместване:

CIRCLE (x+1)  (PI*x+1*x+1)  (3.14159*x+1*x+1), което очевидно не е желания резултат;

скобите, които заграждат целия низ за заместване също са необходими; например, ако запишем 10/CIRCLE (x) и те липсваха, препроцесорът би извършил следното заместване:

10/CIRCLE (x)  10/PI*(x)*(x)  10/3.14159*(x)*(x), което очевидно не е желания резултат;
една функция може да се реализира като макрос; например:

#define sqr(x) ((x)*(x))


възможно е да възникнат странични ефекти във връзка с реализирането на функция като макрос;

например, ако запишем sqr (y++) ние очакваме функцията да върне

y*y и след това y да се увеличи с 1; препроцесорът, обаче, извършва следното заместване:

sqr (y++)  ((y++)*(y++)) – тук функцията отново връща y*y, но y се увеличава с 2;


макросът с аргументи е алтернатива на използването на функции; когато се прави избор каква реализация да се използва, трябва да се имат предвид следните предимства и недостатъци:

  • макросът се изпълнява по-бързо от функцията, тъй като при него няма предаване на аргументи по време на изпълнение на програмата;

  • всяко обръщение към макроса се замества с програмен текст, докато описанието на функцията като програмен текст е единствено за всички обръщения;

  • макросите могат да породят странични ефекти;

  • при обръщение към макрос липсва какъвто и да е контрол върху съответствието на типовете на формалните и фактическите аргументи; това се прави при функциите с помощта на прототипа;

  • макросът води до разширение в първичния файл преди компилацията, докато функцията е постоянна програмна единица обработвана от компилатора – това води до трудно откриване на грешки при работа с големи макроси;


35. Условна компилация.
препроцесорът на C и C++ има набор от директиви с помощта на които може да се определи алтернативно дали даден фрагмент от програмния текст да се компилира или не; тези директиви се наричат директиви за условна компилация; те реализират механизъм за алтернативен избор от вида if…else…endif, подобен на този при условните оператори;

частта if има вида:

#ifdef име_на_макрос

текст на програма на C или C++

#ifndef име_на_макрос

текст на програма на C или C++

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

текст на програма на C или C++


името на макроса в директивите ifdef, ifndef и константния израз в директивата if са условието, което определя дали ще се компилира текста след if или текста след else;

частта else има вида:

#else

текст на програма на C или C++


частта endif има вида:

#endif
с помощта на частта endif се определя края на конструкцията if…else…;


ако преди частта if в програмата е дефиниран макрос с име, съвпадащо с името в директивата ifdef, условието е изпълнено; ако няма такъв макрос, условието не е изпълнено;

ако преди частта if в програмата е дефиниран макрос с име, съвпадащо с името в директивата ifndef, условието не е изпълнено; ако няма такъв макрос, условието е изпълнено;

тъй като в тези случаи е важен само факта дали макросът е дефиниран или не за целите на условната компилация могат да се използват празни макроси;

за директивата if условието е константен израз, който се пресмята по общоприетите правила; ако стойността му е различна от 0, то условието е изпълнено, в противен случай условието не е изпълнено;


препроцесорът проверява дали условието в директивите ifdef, ifndef или if е изпълнено; ако то е изпълнено, програмният текст в частта if се включва в програмата, а този в частта else се пропуска;

ако условието не е изпълнено, програмният текст в частта if се пропуска, а този в частта else се включва в програмата;


да разгледаме един пример; един от възможните начини за тестване на програмата е да се извеждат междинни резултати за контрол; след като завърши тестването, извеждането на междинни резултати вече не е нужно, така че самото извеждане може да се включи в директиви за условна компилация по следния начин:

#ifdef DEBUG

#define PRINT(x) x

#else


#define PRINT(x)

#endif


на етапа тестване на програмата, в началото се дефинира макросът DEBUG чрез директивата #define DEBUG; това води до включване в програмата на всички междинни резултати, реализирани чрез макроса PRINT;

например: PRINT (cout << x << y << z;)

след като се изчистят грешките в програмата, директивата

#define DEBUG се изтрива или се отменя чрез директивата

#undef DEBUG

при повторно компилиране ще се изпълни директивата #else и всички макроси PRINT ще се заменят с празен низ;

предимството на този подход е, че само с една директива #ifdef се управляват извежданията на всички междинни резултати;

друг начин за тестване чрез използване на условна компилация е следния: при всяко извеждане да използваме ifdef;

#ifdef DEBUG

cout << x << y << z;

#endif
директивите за условна компилация могат да се използват и без else, също така те могат да бъдат вложени;
директивите за условна компилация също могат да се използват, ако в програмата има машинно зависими части; например:

#define PC_16 //шестнадесетбитова реализация

#ifdef PC_16

#define INT 16



#else

#define INT 32



#endif
Край

28.01.2003


Сподели с приятели:
1   2   3   4




©obuch.info 2024
отнасят до администрацията

    Начална страница