Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Материалы для подготовки к экзамену по ОП.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
298 Кб
Скачать
☆

Определение макросов

Перед тем как программа будет скомпилирована (или не будет, если найдены ошибки), текст программы обрабатывается препроцессором. Препроцессор позволяет изменять текст программы, используя специальные директивы.

Директива #define определяет новый макрос. Макрос, или макроподстановка, будет заменена в коде программы своим телом. Например, мы часто пользовались макросом

#define SIZE 20

и после этого использовали SIZE вместо размера массива.

Макрос может иметь любое допустимое имя и обычно его пишут прописными буквами для того, чтобы отличать от переменных и констант.

#define BREAK_WORD "end"

Макрос подставляется непосредственно в текст вашей программы. То есть, если у вас был код

#include <conio.h>

#include <stdio.h>

#define LENGTH 128

void main() {

char buffer[LENGTH];

scanf("%127s", buffer);

printf("%s", buffer);

getch();

}

то он будет заменён на код

#include <conio.h>

#include <stdio.h>

void main() {

char buffer[128];

scanf("%127s", buffer);

printf("%s", buffer);

getch();

}

Иными словами, макроподстановка - это просто подмена одного куска текста на другой.

Макросы могут иметь аргументы.

#define MAX (a, b) a > b ? a: b

Например

#include <conio.h>

#include <stdio.h>

#define MAX(x, y) x > y ? x: y

void main() {

int a, b;

scanf("%d", &a);

scanf("%d", &b);

printf("max number is %d", MAX(a, b));

getch();

}

Несмотря на то, что этот код работает, в нём есть ошибки. Макроподстановка – это именно подстановка:

#include <conio.h>

#include <stdio.h>

#define MAX(x, y) x > y ? x: y

void main() {

int a = 10;

int b = 10;

printf("max number is %d\n", MAX(a++, b++));

printf("a = %d\n", a);

printf("b = %d\n", b);

getch();

}

Будет выведено

max number is 11

a = 11

b = 12

Это связано с тем, что код будет подменён следующим образом

("max number is %d\n", a++ > b++ ? a++: b++);

В данном случае возвращаемое значение будет ещё раз инкрементировано.

Теперь рассмотрим макрос.

#include <conio.h>

#include <stdio.h>

#define SPHERE_VOLUME(r) 4.18879020 * (r) * (r) * (r)

void main() {

float halfA = 10.f, halfB = 20.f;

printf("Volume of sphere is %.3f", SPHERE_VOLUME(halfA + halfB));

getch();

}

С одной стороны, этот макрос должен делать программу быстрее, если заменить им вызов функции. Но на деле работать он будет медленнее. Макрос развернётся в следующий код

4,18879020 * (halfA + halfB) * (halfA + halfB) * (halfA + halfB)

итого, три раза будет вызвано сложение. Вот ещё пример ошибки

#include <conio.h>

#include <stdio.h>

#define MUL(x, y) x * y

void main() {

printf("(2 + 3) * (4 + 5) %d\n", MUL(2 + 3, 4 + 5));

getch();

}

В данном случае будет выведено 19 вместо 45, так как макрос будет раскрыт в выражение

2 + 3 * 4 + 5 == 2 + 12 + 5 == 19

Решением будет следующий макрос:

#include <conio.h>

#include <stdio.h>

#define MUL(x, y) (x) * (y)

void main() {

printf("(2 + 3) * (4 + 5) %d\n", MUL(2 + 3, 4 + 5));

getch();

}

И ещё одна ошибка, которая также встречается очень часто. Давайте напишем макрос, который будет выводить на печать массив. Мы воспользуемся им в сортировке пузырьком, чтобы видеть, как изменяется массив во время сортировки.

#include <conio.h>

#include <stdio.h>

#define DISPLAY_ARRAY(arr, size) \

for (i = 0; i < size; i++) {\

printf("%d ", arr[i]);\

}\

printf("\n");

#define SIZE 10

void main() {

int a[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

int tmp;

char flag, i;

do {

flag = 0;

//Проходим по массиву. Если следующий элемент больше предыдущего, то

//меняем их местами и по новой проверяем массив

for (i = 1; i < SIZE; i++) {

if (a[i] > a[i - 1]) {

tmp = a[i];

a[i] = a[i - 1];

a[i - 1] = tmp;

flag = 1;

}

DISPLAY_ARRAY(a, SIZE);

}

} while(flag);

getch();

}

Этот пример работать не будет. Дело в том, что он использует переменную i, которая уже занята. Для корректной работы необходимо локализовать переменную. Для этого тело макроса нужно обернуть фигурными скобками и внутри задать переменную

#include <conio.h>

#include <stdio.h>

#define DISPLAY_ARRAY(arr, size) {\

int i;\

for (i = 0; i < size; i++) {\

printf("%d ", arr[i]);\

}\

printf("\n");\

}

#define SIZE 10

void main() {

int a[SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

int tmp;

char flag, i;

do {

flag = 0;

//Проходим по массиву. Если следующий элемент больше предыдущего, то

//меняем их местами и по новой проверяем массив

for (i = 1; i < SIZE; i++) {

if (a[i] > a[i - 1]) {

tmp = a[i];

a[i] = a[i - 1];

a[i - 1] = tmp;

flag = 1;

}

DISPLAY_ARRAY(a, SIZE);

}

} while(flag);

getch();

}

Да, кстати, заметьте, как пишется многострочный макрос - каждая строка оканчивается обратным слешем.

Поэтому, при работе с параметризованными макросами

  1. Всегда окружайте параметры круглыми скобками

  2. Старайтесь передавать параметры явно и не передавать выражения, которые должны быть вычислены. Это будет приводить к неявным побочным эффектам и замедлению работы за счёт повторного выполнения кода.

  3. Тело сложного макроса заносите под фигурные скобки.