Макросы препроцессора в C появились как часть языка для обеспечения переносимости, читабельности и удобства настройки исходного кода. С помощью директив #define, #ifdef, #ifndef можно создавать условные секции кода, объявлять константы и подключать внешние файлы (#include).
История вопроса:
Директивы препроцессора были введены для того, чтобы упростить адаптацию исходного кода под разные системы и компиляторы, а также автоматизировать повторяющиеся действия.
Проблема:
Без препроцессора нельзя было абстрагироваться от платформенных отличий, повторять фрагменты кода, защищаться от двойного подключения заголовочных файлов. К тому же, приходится быть аккуратным, так как макросы не типизированы и не имеют области видимости.
Решение:
Использование макросов препроцессора для объявления констант, инлайновых функций, условной компиляции и предотвращения многократного включения заголовочных файлов.
Пример кода:
#ifndef MY_HEADER_H #define MY_HEADER_H #define MAX_SIZE 100 #ifdef DEBUG #define LOG(x) printf("%s ", x) #else #define LOG(x) #endif #endif /* MY_HEADER_H */
Ключевые особенности:
Что произойдёт, если забыть include guard в заголовочном файле?
Заголовочный файл может быть включён в один .c файл несколько раз (неявно через другие .h), что приведёт к ошибкам переопределения (redefinition).
Чем отличается #define макроса от объявления inline-функции?
#define просто заменяет текст, не проверяя типы и корректность синтаксиса, а inline-функция — обычная функция, проверяемая компилятором на этапе анализа типов.
Могут ли макросы содержать побочные эффекты?
Да, если макрос неаккуратно определен, то передаваемые выражения могут вычисляться несколько раз. Например:
#define SQUARE(x) (x) * (x) int a = SQUARE(++i); // ++i выполнится ДВАЖДЫ!
Использование макроса без скобок и с выражением, создающим побочные эффекты:
#define DOUBLE(x) x + x int result = DOUBLE(1+2); // результат не 6, а 1+2+1+2=6? Нет, а 1+2+1+2=6 — так? Нет, получается 1+2+1+2. // Но на деле это будет 1 + 2 + 1 + 2 = 6, но если DOUBLE(++i), то ++i применится дважды.
Плюсы:
Минусы:
Определение макроса со скобками и использование для простых констант:
#define DOUBLE(x) ((x) + (x)) #define BUFFER_SIZE 1024
Плюсы:
Минусы: