C, PHP, VB, .NET

Дневникът на Филип Петров


* Предпроцесор

Публикувано на 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 или не.

 



Добави коментар

Адресът на електронната поща няма да се публикува


*