Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Язык C

Предпроцессор C (CPP): как он упрощает компиляцию

Предпроцессор C не является частью компилятора, а представляет собой отдельный этап процесса компиляции. Простыми словами, это инструмент текстовой подстановки, который указывает компилятору выполнить необходимую предварительную обработку перед собственно компиляцией. Дальше мы будем называть его CPP.

Основные директивы препроцессора

Все команды препроцессора начинаются с символа решётки (#). Он должен быть первым непробельным символом в строке, и для читаемости директиву принято писать в первом столбце. Ниже приведён список самых важных директив:

№Директива и описание
1#define — определяет макрос препроцессора (подстановку текста).
2#include — вставляет содержимое указанного заголовочного файла.
3#undef — отменяет определение макроса.
4#ifdef — истина, если макрос определён.
5#ifndef — истина, если макрос не определён.
6#if — проверяет условие на этапе компиляции.
7#else — альтернативная ветка для #if.
8#elif — комбинация #else и #if в одной строке.
9#endif — завершает условный блок препроцессора.
10#error — выводит сообщение об ошибке в stderr.
11#pragma — передаёт специальные команды компилятору стандартизированным способом.

Примеры использования директив

#define — константы и макросы

#define MAX_ARRAY_LENGTH 20

Эта директива заменяет все вхождения MAX_ARRAY_LENGTH на 20. Используйте #define для констант — это повышает читаемость кода.

#include — подключение заголовочных файлов

#include <stdio.h>
#include "myheader.h"

Первая строка сообщает CPP взять stdio.h из системных каталогов и вставить её текст в текущий файл. Вторая — загрузить myheader.h из локального каталога проекта.

#undef и повторное определение

#undef FILE_SIZE
#define FILE_SIZE 42

Сначала отменяется существующее определение FILE_SIZE, затем задаётся новое — 42.

Условная компиляция: #ifndef / #endif

#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif

Макрос MESSAGE будет определён только если он ещё не определён. Это стандартный паттерн защиты от повторного включения (include guards).

Условная компиляция: #ifdef / #endif

#ifdef DEBUG
/* Ваши отладочные инструкции здесь */
#endif

Код внутри блока обрабатывается только если макрос DEBUG определён. Удобно управлять этим флагом через ключ компилятора -DDEBUG (например, gcc -DDEBUG), не меняя исходный код.

Предопределённые макросы

Стандарт ANSI C задаёт ряд встроенных макросов. Их можно использовать в программе, но менять их напрямую нельзя.

№Макрос и описание
1__DATE__ — текущая дата в формате "MMM DD YYYY" (строка).
2__TIME__ — текущее время в формате "HH:MM:SS" (строка).
3__FILE__ — имя текущего файла (строка).
4__LINE__ — номер текущей строки (целое число).
5__STDC__ — равен 1, если компилятор соответствует стандарту ANSI C.

Пример использования:

#include <stdio.h>
int main() {
    printf("File :%s\n", __FILE__);
    printf("Date :%s\n", __DATE__);
    printf("Time :%s\n", __TIME__);
    printf("Line :%d\n", __LINE__);
    printf("ANSI :%d\n", __STDC__);
}

Результат выполнения (для файла test.c):

File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1

Операторы препроцессора

CPP предоставляет специальные операторы для создания сложных макросов.

Оператор продолжения строки (\)

Макрос обычно пишется в одну строку. Оператор \ позволяет перенести определение на следующую строку:

#define message_for(a, b) \
    printf(#a " and " #b ": We love you!\n")

Оператор строкизации (#)

Оператор # внутри макроса превращает параметр в строковый литерал. Работает только в макросах с параметрами.

#include <stdio.h>
#define message_for(a, b) \
    printf(#a " and " #b ": We love you!\n")
int main(void) {
    message_for(Carole, Debra);
    return 0;
}

Результат:

Carole and Debra: We love you!

Оператор склеивания токенов (##)

Оператор ## объединяет два токена в один. Пример:

#include <stdio.h>
#define tokenpaster(n) printf("token" #n " = %d", token##n)
int main(void) {
    int token34 = 40;
    tokenpaster(34);
    return 0;
}

Результат:

token34 = 40

Препроцессор раскрывает это в printf("token34 = %d", token34);. Здесь используются оба оператора: строкизации (#) и склеивания (##).

Оператор defined()

Используется в константных выражениях #if для проверки, определён ли идентификатор через #define. Возвращает ненулевое значение (истина), если определён, и 0 (ложь) — если нет.

#include <stdio.h>
#if !defined(MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
    printf("Here is the message: %s\n", MESSAGE);
    return 0;
}

Результат:

Here is the message: You wish!

Параметризованные макросы (function-like macros)

Одна из мощных возможностей CPP — имитация функций через макросы с параметрами. Например, возведение в квадрат:

int square(int x) { return x * x; }

Через макрос:

#define square(x) ((x) * (x))

Важно: имя макроса и открывающая скобка должны быть вплотную (пробел недопустим). Аргументы берутся в скобки, а всё выражение — в дополнительные скобки, чтобы избежать проблем с приоритетом операций.

Пример: макрос MAX

#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
    printf("Max between 20 and 10 is %d\n", MAX(10, 20));
    return 0;
}

Результат:

Max between 20 and 10 is 20

Язык C

  1. C# Hello World — создание вашего первого C# приложения
  2. Понимание ключевых слов и идентификаторов C#: правила, списки и лучшие практики
  3. Мастерство C# переменных и примитивных типов данных: полное руководство
  4. Операторы C# — исчерпывающее руководство по операторам в C#
  5. Освоение побитовых и сдвиговых операторов в C#: полное руководство
  6. Основы ввода-вывода в C#: Console.WriteLine, ReadLine и форматирование
  7. Выражения, операторы и блоки в C#: подробное руководство с примерами
  8. Освоение комментариев в C#: виды, лучшие практики и XML-документация
  9. Освоение оператора switch в C#: синтаксис, примеры и лучшие практики
  10. Тернарный оператор в C#: краткое руководство по условным выражениям