Что такое директива в программировании
Перейти к содержимому

Что такое директива в программировании

2.9 – Знакомство с препроцессором

Когда вы компилируете свой код, вы можете ожидать, что компилятор компилирует код именно в том виде, как вы его написали. На самом деле это не так.

Перед компиляцией файл кода проходит этап, известный как трансляция. На этапе трансляции происходит много всего, чтобы подготовить ваш код к компиляции (если вам интересно, здесь вы можете найти список этапов трансляции). Файл кода с примененными к нему трансляциями называется единицей трансляции.

Самый примечательный из этапов трансляции связан с препроцессором. Препроцессор лучше всего рассматривать как отдельную программу, которая манипулирует текстом в каждом файле кода.

Когда препроцессор запускается, он просматривает файл кода (сверху вниз) в поисках директив препроцессора. Директивы препроцессора (часто называемые просто директивами) – это инструкции, которые начинаются с символа # и заканчиваются символом новой строки (НЕ точкой с запятой). Эти директивы сообщают препроцессору, что нужно выполнить определенные задачи по обработке текста. Обратите внимание, что препроцессор не понимает синтаксис C++ – вместо этого директивы имеют свой собственный синтаксис (который иногда напоминает синтаксис C++, а иногда не очень).

Выходные данные препроцессора проходят еще несколько этапов трансляции, а затем компилируются. Обратите внимание, что препроцессор никоим образом не изменяет исходные файлы кода – скорее, все изменения текста, сделанные препроцессором, временно размещаются в памяти при каждой компиляции файла кода.

В этом уроке мы обсудим, что делают некоторые из наиболее распространенных директив препроцессора.

В качестве отступления.

Директивы using (представленные в уроке «2.8 – Конфликты имен и пространства имен») не являются директивами препроцессора (и, следовательно, препроцессором не обрабатываются). Таким образом, хотя термин директива обычно означает директиву препроцессора, это не всегда так.

Включения

Вы уже видели в действии директиву #include (обычно это было #include <iostream> ). Когда вы включаете файл с помощью #include , препроцессор заменяет директиву #include содержимым включенного файла. Включенное содержимое затем предварительно обрабатывается (вместе с остальной частью файла), а затем компилируется.

Рассмотрим следующую программу:

Когда препроцессор запускается для этой программы, он заменяет #include <iostream> предварительно обработанным содержимым файла с именем " iostream ".

Поскольку #include почти всегда используется для включения заголовочных файлов , мы обсудим эту директиву более подробно в следующем уроке (когда мы будем подробнее обсуждать заголовочные файлы).

Определения макросов

Директива #define может использоваться для создания макросов. В C++ макрос – это правило, определяющее, как входной текст преобразуется в выходной текст с помощью замены.

Существует два основных типа макросов: макросы, подобные объектам, и макросы, подобные функциям.

Макросы, подобные функциям, действуют как функции и служат той же цели. Мы не будем здесь их обсуждать, потому что их использование обычно считается опасным, и почти всё, что они могут сделать, можно сделать и с помощью обычных функций.

Макросы, подобные объектам, можно определить одним из двух способов:

В первом определении нет подставляемого при замене текста, а во втором есть. Поскольку это директивы препроцессора (а не инструкции), обратите внимание, что ни одна из форм не заканчивается точкой с запятой.

Макросы, подобные объектам, с подставляемым текстом

Когда препроцессор встречает эту директиву, любое дальнейшее появление идентификатора заменяется подставляемым текстом. Идентификатор традиционно набирается заглавными буквами с использованием подчеркивания для обозначения пробелов.

Рассмотрим следующую программу:

Препроцессор преобразует приведенный выше код в следующее:

Этот код при запуске печатает: My name is: Alex .

Объектоподобные макросы использовались как более дешевая альтернатива постоянным переменным. Те времена давно прошли, поскольку компиляторы стали умнее, а язык вырос. Теперь объектоподобные макросы можно увидеть только в устаревшем коде.

Мы рекомендуем вообще избегать таких макросов, так как существуют более эффективные способы сделать аналогичные вещи. Мы обсудим это более подробно в уроке «4.14 – const, constexpr и символьные константы».

Макросы, подобные объектам, без подставляемого текста

Макросы, подобные объектам, также могут быть определены без подставляемого при замене текста.

Макросы этого типа работают так, как и следовало ожидать: любое дальнейшее появление идентификатора удаляется и ничем не заменяется!

Это может показаться довольно бесполезным, и, да, это бесполезно для замены текста. Однако эта форма директивы обычно используется для другого. Мы обсудим использование этой формы чуть позже.

В отличие от объектоподобных макросов с заменяющим текстом, макросы этой формы обычно считаются приемлемыми для использования.

Условная компиляция

Директивы препроцессора условной компиляции позволяют указать, при каких условиях что-то будет или не будет компилироваться. Существует довольно много разных директив условной компиляции, но здесь мы рассмотрим только три, которые используются чаще всего: #ifdef , #ifndef и #endif .

Директива препроцессора #ifdef позволяет препроцессору проверять, был ли идентификатор ранее определен с помощью #define . Если это так, код между #ifdef и соответствующим #endif компилируется. В противном случае код игнорируется.

Рассмотрим следующую программу:

Поскольку PRINT_JOE был определен с #define , строка cout << "Joe\n" будет скомпилирована. Поскольку PRINT_BOB не был определен с #define , строка cout << "Bob\n" будет проигнорирована.

#ifndef – это противоположность #ifdef в том, что он позволяет вам проверить, НЕ был ли идентификатор еще определен с помощью #define .

Эта программа печатает « Bob », потому что PRINT_BOB никогда не был определен с #define .

Вместо #ifdef PRINT_BOB и #ifndef PRINT_BOB вы также можете увидеть #if defined (PRINT_BOB) и #if !defined(PRINT_BOB) . Они делают то же самое, но используют синтаксис, немного более похожий на C++.

Еще одно распространенное использование условной компиляции включает использование #if 0 для исключения блока кода из компиляции (как если бы он находился внутри блока комментариев):

Приведенный выше код печатает только « Joe », потому что « Bob » и « Steve » находились внутри блока #if 0 , который препроцессор исключил из компиляции.

Это обеспечивает удобный способ «закомментировать» код, содержащий многострочные комментарии.

Макросы, подобные объектам, не влияют на другие директивы препроцессора.

Теперь вам может быть это интересно:

Поскольку мы определили PRINT_JOE как ничто, почему препроцессор не заменил PRINT_JOE в #ifdef PRINT_JOE ничем?

Макросы вызывают замену текста только в обычном коде. Другие команды препроцессора игнорируются. Следовательно, PRINT_JOE в #ifdef PRINT_JOE не меняется.

На самом деле вывод препроцессора вообще не содержит директив – все они разрешаются/удаляются перед компиляцией, потому что компилятор не знает, что с ними делать.

Область видимости определений #define

Директивы разрешаются перед компиляцией сверху вниз для каждого файла.

Рассмотрим следующую программу:

Несмотря на то, что похоже, что #define MY_NAME "Alex" определен внутри функции foo , препроцессор этого не заметит, поскольку он не понимает таких понятий C++, как функции. Следовательно, эта программа ведет себя идентично программе, в которой #define MY_NAME "Alex" был определен либо до, либо сразу после функции foo . Для большей удобочитаемости идентификаторы определяются с помощью #define обычно вне функций.

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

Директива (программирование)

В программировании термин «директива» (указание) по использованию похож на термин «команда», так как также используется для описания некоторых конструкций языка программирования (то есть указаний компилятору или ассемблеру особенностей обработки при компиляции).

Содержание

Язык ассемблера

В языке ассемблера директивы указывают общую информацию, такую как целевая среда, указание границ между секциями и так далее. Например, директива «ALIGN», которая вставляет в текущую секцию необходимое количество байт для выравнивания строк, часто упоминаемая как «директива», противоречит тому факту, что она совпадает с частями конструкций в генерируемом коде.

Препроцессор Си

В языки программирования Си и C++ встроена поддержка препроцессора. Строки в исходном коде, которые должны быть обработаны препроцессором в виде #define и #include , называются препроцессорными директивами.

Синтаксические конструкции, похожие на препроцессорные директивы языка Си, такие как #region в языке C#, также часто называются «директивами», хотя в указанных случаях стадии обработки препроцессором может и не быть.

В других языках высокого уровня

В языке Ada директивы компилятора называются прагмами (сокращение от «pragmatic information» («полезная информация»)).

В Паскале директивы называются указательными комментариями из-за того, что по синтаксису похожи на комментарии. В Паскале указательный комментарий — это комментарий, у которого первым символом указан знак доллара; например, аналогом директивы #include «file» языка Си будет указательный комментарий <$I "file">.

В Perl ключевое слово « use » («применять») можно использовать как «прагму», например use strict; или use utf8; . Такая конструкция иногда может упоминаться как «директива». Тем не менее, в некоторых источниках[1] используется термин «директивы Perl» для обозначения конструкций типа hashbang.

Дополнительные материалы

  • Язык программирования Си
  • Концепции языков программирования
  • Препроцессоры

Wikimedia Foundation . 2010 .

Полезное

Смотреть что такое «Директива (программирование)» в других словарях:

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

Наследование (программирование) — Для улучшения этой статьи желательно?: Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное. У этого термин … Википедия

Конструктор (программирование) — У этого термина существуют и другие значения, см. Конструктор. В объектно ориентированном программировании конструктор класса (от англ. constructor, иногда сокращают ctor)  специальный блок инструкций, вызываемый при создании объекта.… … Википедия

Пространство имён (программирование) — У этого термина существуют и другие значения, см. Пространство имён. Пространство имён (англ. namespace)  некоторое множество, под которым подразумевается модель, абстрактное хранилище или окружение, созданное для логической группировки … Википедия

Условная компиляция — В информатике, препроцессор это компьютерная программа, принимающая данные на входе, и выдающая данные, предназначенные для входа другой программы, например, такой как компилятор. О данных на выходе препроцессора говорят, что они находятся в… … Википедия

Препроцессор — У этого термина существуют и другие значения, см. Процессор (значения). Препроцессор  это компьютерная программа, принимающая данные на входе и выдающая данные, предназначенные для входа другой программы (например, компилятора). О данных на… … Википедия

C++ — У этого термина существуют и другие значения, см. C. См. также: Си (язык программирования) C++ Семантика: мультипарадигмальный: объектно ориентированное, обобщённое, процедурное, метапрограммирование Тип исполнения: компилируемый Появился в … Википедия

С++ — См. также: Си (язык программирования) C++ Семантика: мультипарадигмальный: объектно ориентированное, обобщённое, процедурное, метапрограммирование Тип исполнения: компилируемый Появился в: 1985 г. Автор(ы): Бьёрн Страуструп … Википедия

Objective-C — Класс языка: объектно ориентированный, мультипарадигмальный: рефлексивно ориентированный Появился в: 1986 Автор(ы): Бред Кокс Типизация данных: нестрогая, статическая / динамическая … Википедия

JSP — Стиль этой статьи неэнциклопедичен или нарушает нормы русского языка. Статью следует исправить согласно стилистическим правилам Википедии. JSP (JavaServer Pages)  технология, позволяющая веб разработчикам легко создавать содержимое, которое… … Википедия

Директивы препроцессора в Си

Препроцессор — это специальная программа, являющаяся частью компилятора языка Си. Она предназначена для предварительной обработки текста программы. Препроцессор позволяет включать в текст программы файлы и вводить макроопределения.
Работа препроцессора осуществляется с помощью специальных директив (указаний). Они отмечаются знаком решетка #. По окончании строк, обозначающих директивы в языке Си, точку с запятой можно не ставить.

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

#include — вставляет текст из указанного файла
#define — задаёт макроопределение (макрос) или символическую константу
#undef — отменяет предыдущее определение
#if — осуществляет условную компиляцию при истинности константного выражения
#ifdef — осуществляет условную компиляцию при определённости символической константы
#ifndef — осуществляет условную компиляцию при неопределённости символической константы
#else — ветка условной компиляции при ложности выражения
#elif — ветка условной компиляции, образуемая слиянием else и if
#endif — конец ветки условной компиляции
#line — препроцессор изменяет номер текущей строки и имя компилируемого файла
#error — выдача диагностического сообщения
#pragma — действие, зависящее от конкретной реализации компилятора.

Директива #include

Директива #include позволяет включать в текст программы указанный файл. Если заголовочный файл содержит описание библиотечных функций и находится в папке компилятора, он заключается в угловые скобки <> .
Если файл находится в текущем каталоге проекта, он указывается в кавычках "" . Для файла, находящегося в другом каталоге необходимо в кавычках указать полный путь.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *