Препроцессор
Препроцессор - это программа, которая производит некоторые (иногда весьма значительные) манипуляции с первоначальным текстом программы перед тем, как он подвергается компиляции. Будучи дословно переведенным, с английского, слово препроцессор означает предварительный обрабатыватель
Препроцессоры создают входной текст для компиляторов и могут выполнять следующие функции:
- обработку макроопределений;
- включение файлов;
- "рациональную" предобработку;
- расширение языка.
Оператор (директива) препроцессора - это одна строка исходного текста, начинающаяся с символа #, за которым следуют название оператора (define, pragma, include, if) и операнды. Операторы препроцессора могут появляться в любом месте программы, и их действие распространяется на весь исходный файл.
Директивы препроцессора:
- #include и заголовочный файлы - включения текста из файла, разнесение проекта на несколько файлов.
- #Определение констант с помощью #define - определение символических констант.
- #line Для нумерации строк можно использовать директиву:
#line <константа> которая указывает компилятору, что следующая ниже строка текста имеет номер, определяемый целой десятичной константой. Команда может определять не только номер строки, но и имя файла: #line <константа> "<имя_файла>"
- #error директива предпроцессора приводит к выдаче диагностического сообщения в виде последовательности лексем.
- #pragma определяет действия, зависящие от конкретной реализации компилятора, и позволяет выдавать компилятору различные инструкции. Например подавление ошибок в Visual Studio будет выглядеть так:
#include <iostream> using namespace std; #pragma warning(disable : 4101 ) //подавить вывод ошибки 4101 #pragma warning(disable : 4081 ) void main() { int i; }
#pragma comment(lib, "Ws2_32.lib")//Директива #pragma comment вызывает добавление указанного ключа к командной строке компоновщика на этапе связывания.
- В языке С существует возможность работы с операторами # и ##. Данные операторы используются в альянсе с директивой #define.
Оператор # превращает аргумент, которому он предшествует, в строку, заключенную в кавычки. #include <iostream>
using namespace std; # define mkstr(s) #s void main() { cout<<mkstr(I love C); // Для компилятора cout<<"I love C"; }
Оператор ## используется для конкатенации (объединения) двух лексем #include <iostream>
using namespace std; # define concat(a,b) a##b void main() { int xy=10; cout<<concat(x,y); // Для компилятора cout<<xy; }
Макроимена
В языке С существуют встроенные (заранее определенные) макроимена, доступные препроцессору во время обработки. Они позволяют получить следующую информацию:
Условная компиляция
Директивы условной компиляции, позволяют генерировать программный код в зависимости от выполнимости определенных условий. Условная компиляция обеспечивается в языке C набором команд, которые, по существу, управляют не компиляцией, а препроцессорной обработкой:
#if <константное_выражение> #ifdef <идентификатор> #ifndef <идентификатор> #else#endif#elif
Первые три команды выполняют проверку условий, две следующие - позволяют определить диапазон действия проверяемого условия. Последняя команда используется для организации проверки серии условий. Общая структура применения директив условной компиляции такова:
#if/#ifdef/#ifndef <константное_выражение или идентификатор> <текст_1> #else //необязательная директива <текст_2> #endif
Конструкция#else <текст_2> не обязательна. Текст_1 включается в компилируемый текст только при истинности проверяемого условия. Если условие ложно, то при наличии директивы #else на компиляцию передается текст_2. Если директива #else отсутствует, то весь текст от #if до #endif при ложном условии опускается. Различие между формами команд #if состоит в следующем.
- В первой из перечисленных директив #if проверяется значение константного целочисленного выражения. Если оно отлично от нуля, то считается, что проверяемое условие истинно. Например, в результате выполнения директив:
#if 5+12 <текст_1> #endif
текст_1 всегда будет включен в компилируемую программу.
- В директиве #ifdefпроверяется, определен ли с помощью команды #define к текущему моменту идентификатор, помещенный после #ifdef. Если идентификатор определен, то текст_1 используется компилятором.
- В директиве #ifndef проверяется обратное условие - истинным считается неопределенность идентификатора, т.е. тот случай, когда идентификатор не был использован в команде #define или его определение было отменено командой #undef.
Для организации мульти ветвлений во время обработки препроцессором исходного текста программы введена директива
#elif <константное_выражение>
является сокращением конструкции #else#if.
Структура исходного текста с применением этой директивы такова:
#if <константное_выражение_1> <текст_1> #elif <константное_выражение_2> <текст_2> #elif <константное_выражение_3> <текст_3> . . . . #else <текст_N> #endif
Препроцессор проверяет вначале условие в директиве #if, если оно ложно (равно 0) - вычисляет константное_выражение_2, если оно равно О - вычисляется константное_выражение_3 и т.д. Если все выражения ложны, то в компилируемый текст включается текст для случая #else. В противном случае, т.е. при появлении хотя бы одного истинного выражения (в #if или в #elif), начинает обрабатываться текст, расположенный непосредственно за этой директивой, а все остальные директивы не рассматриваются. Таким образом, препроцессор обрабатывает всегда только один из участков текста, выделенных командами условной компиляции. A, теперь, рассмотрим несколько примеров.
Пример 1. Простая директива условного включения.
#ifdef ArrFlg int Arr[30]; #endif
Если во время интерпретации директивы определено макроопределение ArrFlg, то приведенная запись дает генерацию выражения
int Arr[30];
В противном случае не будет генерировано ни одно выражение.
Пример 2.
#include <iostream> using namespace std; #define ArrFlg 1 void main () { #ifdef ArrFlg int Arr[30]; #else cout << "Array is not defined!"; #endif }
Пример 3. Директива условного включения с альтернативой
#if a+b==5 cout << 5; #else cout << 13; #endif
Если выражение a+b==5 представляет величину, отличную от 0, то будет сгенерирована команда cout « 5;, в противном случае будет сгенерирована команда cout « 13;.
Пример 4. Составная директива условного включения
#include <iostream> using namespace std; //++++++++++++++++++++++ #define Alfa 5 //++++++++++++++++++++++ #if Alfa*5>20 void main () //++++++++++++++++++++++ #if Alfa==4 int Arr[2]; #elif Alfa==3 char Arr[2]; #else { #endif //++++++++++++++++++++++ #if 0 cout<<"One"; #else cout<<"Two"; #endif //++++++++++++++++++++++ #else cout<<"Test"; #endif //++++++++++++++++++++++ }
Интерпретация приведенной записи приведет к генерации
void main () { cout<<"Kaja"; }
Создание Demo - версии программы
Ниже показано как можно включать или исключать куски кода. Раз куска кода нет - сооответсвенно и взламывать нечего. Вместо этого куска кода соответственно можно подставить всплывающее меню с предложением о покупке.
#include <iostream> using namespace std; #define ABC1 void main() { #ifdef ABC1 cout << "first part" << endl; #else cout << "second part" << endl; #endif }
📌 Для тестирования скриптов, установщиков VPN, Python ботов рекомендуем использовать надежные VPS на короткий срок. Если вам нужна помощь с более сложными задачами, вы можете найти фрилансера, который поможет с настройкой. Узнайте больше о быстрой аренде VPS для экспериментов и о фриланс-бирже для настройки VPS, WordPress. 📌
💥 Подпишись в Телеграм 💥 и задай вопрос по сайтам и хостингам бесплатно!7 Самых Популярных Статей
- Как запустить скрипты и веб-приложения на Python
- Что такое страны TIER 1,2,3
- 7 способов сравнения файлов по содержимому в Windows или Linux
- Установка и тестирование веб-панели HestiaCP
- Китайский VPN Shadowsocks простая установка и настройка
- top, htop, atop определение загрузки ОС (Load average, LA)
- Использование rsync в примерах