* Предпроцесор
Публикувано на 24 октомври 2008 в раздел С/С++.
Езикът за програмиране С има едно рядко срещано при езиците от високо ниво преимущество - възможност за управление на процеса на компилация. Предпроцесорът дава на програмиста следните допълнителни средства:
- Използуване на макроопределения
- Включване на първични файлове към програмата
- Условно компилиране
Предпроцесорът е прорама, която анализира анализира и променя оригиналния сорс код преди той да бъде изпратен до компилатора. Например всички коментари се заменят с интервал (за да не заемат памет). Програмистът може сам да дефинира подобни промени чрез използването на т.нар. директиви на предпроцесора:
#ключова_дума вид_на_заместването
Ключовите думи са следните:
1. #define - Дефинира макроопределение
2. #undef - Отменя макроопределение
3. #include - добавя файл
4. #ifdef, #ifndev - Конструкции от типа "if-else-end" в зависимост от макроопределение
5. #if, #else, #endif - Конструкции от типа "if-else-end" в зависимост от константа
6. #line - Присвояване на намер на програмен ред
Тези директиви могат да се записват на всяко място в програмата. Важно е обаче, че всяка директива се пише на отделен ред.
I. Макроопределения (макроси):
Макрос е дефиниция, която свързва едно символно име с произволен низ от допустими за езика С символи. Символното име се нарича "име на макроса". Дефиницията става чрез директивата #define:
#define име_на_макроса низ
Низът е допустима за езика С последователност от символи. Ако предпроцесорът срещне името на макроса в програмата, то той ще го замени с преписания му низ. Например ето как в С можем да дефинираме константа CONST:
#define CONST1 25.2 #define CONST2 12 ... double x = CONST1; int x[CONST2]; // Нулираме масива for(int i=0; i<CONST2; x[i++]=0);
Предимството на използването на такъв тип дефиниции, е че с една промяна на стойност в началото на програмата ние можем да извършваме много промени в кода.
Заместващият низ в макрос може да бъде и израз:
#define EXPR (3.14*r*r) ... double r = 8.5; printf("Circle with radius %lf has area %lf: ", r, EXPR);
Възможно е и за използваме "вложени" макроси:
#define SIDE 10 #define AREA (SIDE*SIZE)
Особено полезна функционалност на макросите е възможността им за добавянето на аргументи:
#define име_на_макроса(аргументи) низ
Ето отново примера с изчисляване на лице на окръжност:
#define PI 3.141592 #define CIRCLE(r) (PI*(r)*(r)) ... double radius = 8.2, area; area = CIRCLE(radius); printf("Circle with radius %lf has area %lf: ", radius, CIRCLE(radius));
Скобите при песането на низа на макроса са изключително важни. Без тях може да се достигне до неочаквани грешки:
#define CIRCLE(r) PI*r*r #define MACRO(s) 12+s ... z = CIRCLE(x+1); // Това ще бъде заместено с z = PI*x + 1*x + 1 z = 10/MACRO(x); // Това ще бъде заместено с z = 10/12 + x
В някои случаи е много удобно да използваме макроси като заместители на функции. Например чрез следния макрос се използва условен оператор за определяне на по-голямото от две числа:
#define MAX(a,b) (((a)>(b))?(a):(b)) ... int x = 5, y = 6; z = MAX(x+1, y+2);
Не забравяйте, че аналогията между макрос и функция е само външна. Макросите се изпълняват по-бързо от функциите, но в същото време използуват повече памет. Основно предимство на макросите обаче, е че можем да подаваме аргументи от различен тип, докато при функциите типовете са фиксирани.
II. Условна компилация:
Синтаксисът е:
#ifdef име_на_макрос текст на програма на С; #else текст на програма на С; #еndif
или:
#if константен_израз текст на програма на С; #else текст на програма на С; #еndif
Един (остарял, но все още широко използван) начин да тестваме програма е да отпечатваме междинни резултати в кода. Макросите помагат значително:
#define DEBUG #ifdef DEBUG #define PRINT(VAL) printf("x = %lf", VAL) #else #define PRINT(VAL) #endif ... double x = 12.5; // Тук съобщението ще се отпечата само ако DEBUG е дефинирано макроопределение PRINT(x);
Ако във примера добавите "#undef DEBUG" или просто премахнете дефиницията на DEBUG въобще, то на екрана няма да бъде отпечатано нищо.
Задача: Напишете макрос, на който подаваме символен низ като аргумент и го отпечатва на екрана.
Задача: Дефинирайте маклоопределение DEBUG. Преправете горния пример, така че да използва директивата #if и съобщението да се извиква в зависимост от това дали DEBUG има константна стойност 1 или не.
Добави коментар