Препроцессор и макросы в C: мастерство #include, #define и условной компиляции
Препроцессор и макросы в C
Изучите мощь препроцессора C: как подключать заголовочные файлы, определять константы и функции, и управлять потоком компиляции с условными директивами.

Препроцессор C запускается до компилятора, преобразуя исходный код путем раскрытия макросов, включения заголовочных файлов и оценки условных операторов. Это незаменимый инструмент для написания гибкого, повторно используемого кода.
Все директивы препроцессора начинаются с символа #. Например:
#define PI 3.14
Подключение заголовочных файлов: #include
Директива #include вставляет содержимое заголовочного файла прямо в ваш исходный файл. Типичное использование:
#include <stdio.h>
Без #include <stdio.h> функции вроде printf() и scanf() были бы неопределены. Можно также создавать собственные заголовочные файлы:
#include "my_header.h"
Пользовательские заголовки полезны для группировки связанных объявлений функций и констант.
Определение констант и выражений: #define
Макрос заменяет токен или выражение значением до компиляции. Пример:
#define c 299792458 /* скорость света */
Использование c в любой точке программы раскроется в 299792458.
Пример 1: Определение PI
#include <stdio.h>
#define PI 3.1415
int main() {
float radius, area;
printf("Enter the radius: ");
scanf("%f", &radius);
area = PI * radius * radius;
printf("Area=%.2f", area);
return 0;
}
Функциональные макросы
Макросы могут принимать аргументы, работая похоже на встроенные функции:
#define circleArea(r) (3.1415 * (r) * (r))
Для circleArea(5) препроцессор раскроет это в (3.1415 * 5 * 5).
Пример 2: Использование функционального макроса
#include <stdio.h>
#define PI 3.1415
#define circleArea(r) (PI * (r) * (r))
int main() {
float radius, area;
printf("Enter the radius: ");
scanf("%f", &radius);
area = circleArea(radius);
printf("Area = %.2f", area);
return 0;
}
Условная компиляция
Условные директивы позволяют включать или исключать блоки кода на этапе компиляции, похоже на операторы if, но вычисляются до выполнения.
Частые сценарии использования
- Нацеливание на разные операционные системы или оборудование.
- Создание отладочных сборок без накладных расходов во время выполнения.
- Поддержка устаревших путей кода для справки.
Ключевые директивы
#ifdef MACRO /* код, когда MACRO определен */ #endif
#if EXPRESSION /* код, когда EXPRESSION не ноль */ #else /* код, когда EXPRESSION ноль */ #endif
#if EXPRESSION /* код */ #elif ANOTHER_EXPRESSION /* альтернативный код */ #else /* запасной код */ #endif
#if defined BUFFER_SIZE && BUFFER_SIZE >= 2048 /* буфер достаточно велик */ #endif
Предопределенные макросы
| Макрос | Значение |
|---|---|
__DATE__ | Строка с текущей датой компиляции |
__FILE__ | Строка с текущим именем файла |
__LINE__ | Номер строки, где появляется макрос |
__STDC__ | Ненулевое, если компилятор соответствует стандарту ANSI C |
__TIME__ | Строка с текущим временем компиляции |
Пример 3: Отображение времени компиляции
#include <stdio.h>
int main() {
printf("Current time: %s", __TIME__);
return 0;
}
Пример вывода:
Current time: 19:54:39
Рекомендуемые чтения
- Line Control
- Pragmas
- Preprocessor Output
- Other Directives
Язык C
- Комплексный обзор резисторов, катушек и конденсаторов в цепях переменного тока
- Понимание ключевых слов и идентификаторов C#: правила, списки и лучшие практики
- Классы и объекты в C#: Фундаменты надёжного ООП
- Абстрактные классы и методы в C#: практическое руководство
- Частичные классы и методы в C#: понимание и применение
- Sealed-классы и sealed-методы в C#: когда использовать, примеры и повышение безопасности кода
- Освоение директив препроцессора C#: практическое руководство
- Ключевые слова и идентификаторы в C: практическое руководство
- Константы и литералы в C: целочисленные, вещественные, символьные, строковые и определение констант
- Ввод-вывод в C: stdio.h, потоки stdin/stdout/stderr, функции getchar/putchar, gets/puts, scanf/printf