Макросы в Си

Давайте попробуем разобраться с макросами. Что же такое макросы и с чем из едят?
Когда мне преподавали программирование в институте (это были времена когда я мало понимал в программировании и думал, что программисты — это крутые хакеры, которые сидят в непонятных подвалах с горой крутого оборудования), мне сказали что макросы это такие функции, которые начинаются со знака подчеркивания.
Толи я был настолько дурак в этом деле, то ли преподаватель решил не слишком изощряться в объяснениях… Увы ответ был таков.
На самом деле ответ не совсем таков 😉 Да, название макроса часто начинают со знака подчеркивания (это стиль, который пытается нам навязать Microsoft), но только лишь то, что функция названа таким образом не говорит нам что это макрос.
Макрос — это предопределенная структура, заданная препроцессору, который подставит её в нужном месте.
Вы же помните, что компиляция программы происходит в несколько этапов и одним из низ есть процесс подстановки в код значений определенных при помощи директивы #define.
Простейшим макросом является конструкция вроде этой:

#define PI 3.141592

В дальнейшем в коде при упоминании PI препроцессор подставит 3,141592. В дальнейшем означает, что процедура происходит последовательно. Т.е. если до данного момента макрос объявлен не был, то и препроцессор о нем не узнает.

foo = X;
#define X 4
bar = X;

Таким образом в переменную foo попадет значение X, а вот в переменную bar попадет значение 4.
Но это самые простые макросы, они используются только для задания размеров массивов, констант, которые не очень часто используются в коде.
На самом деле в макрос можно уместить целую функцию.
Например, чтобы найти минимальное значение из 2ух можно воспользоваться таким макросом:

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))

Самая обычная тернарная операция.
Макросы часто используются при написании программ для микроконтроллеров.
Макросы установки ножки E (PORTD0) в единичное и нулевое состояние для МК avr:

#define E_ENABLE PORTD.1 = 1;
#define E_DISABLE PORTD.1 = 0;

Для удаления макросов можно воспользоваться директивой #undef.
Ну и напоследок несколько макросов для примера:

// удвоение x
#define double(x) (2*(x))

// сложение двух чисел с помещением результата в первое (равносильно ассемблерной команде)
#define ADD(x,y) x = x + y

// нахождение модуля числа
#define abs(x) ((x) < 0 ? -(x) : (x))

// нахождение длины окружности
#define mCircleLength(r) (6.28318 * (r))

После имени макроса в макроопределении, перед первой открывающей скобкой не должно быть пробела. Это важно. Если пробел будет, то мы получим определение константы.
Обратите также внимание, что скобки в макросах очень важны ввиду того, что препроцессор будет подставлять их в другие выражения в следствии чего вы можете получить совершенно иной результат.
Например:

#define Sum(param) param + 2

int var = 10 * mSum(5);

// после подстановки тела макроса получим:
int var = 10 * 5 + 2;

В результате в переменную попадет значение 52, а не 70, как мы ожидали.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий