Что такое директива в программировании
Директива (программирование)
В программировании термин «директива» (указание) по использованию похож на термин «команда», так как так же используется для описания некоторых конструкций языка программирования (то есть указаний компилятору или ассемблеру особенностей обработки при компиляции).
Содержание
Язык ассемблера
В языке ассемблера директивы указывают общую информацию, такую как целевая среда, указание границ между секциями и так далее. Например, директива «ALIGN», которая вставляет в текущую секцию необходимое количество байт для выравнивания строк, часто упоминаемая как «директива», противоречит тому факту, что она совпадает с частями конструкций в генерируемом коде.
Препроцессор Си
В языки программирования Си и C++ встроена поддержка препроцессора. Строки в исходном коде, которые должны быть обработаны препроцессором в виде #define и #include называются препроцессорными директивами.
Синтаксические конструкции, похожие на препроцессорные директивы языка Си, такие как #region в языке C#, также часто называются «директивами», хотя в указанных случаях стадии обработки препроцессором может и не быть.
В других языках высокого уровня
В языке Ada директивы компилятора называются прагмами (сокращение от «pragmatic information» («полезная информация»)).
В Паскале директивы называются указательными комментариями из-за того, что по синтаксису похожи на комментарии. В Паскале указательный комментарий — это комментарий, у которого первым символом указан знак доллара; например, аналогом директивы #include «file» языка Си будет указательный комментарий <$I "file">.
ru.knowledgr.com
Этот термин можно использовать для обозначения запатентованных тегов и запятых сторонних производителей (или разметки), встроенных в код, что приводит к дополнительной исполняемой обработке, расширяющей существующие comp, assembler и language, присутствующие в среде разработки. Термин «директива» также применяется различными способами, аналогичными термину command.
Препроцессор C
В C и C++ язык поддерживает простой макропрепроцессор. Исходные линии, которые должны обрабатываться препроцессором, такие как и называются директивами препроцессора.
Другой C ct, директива, используется для того, чтобы comp использовать прагматические или зависимые от реализации функции. Двумя заметными пользователями этой директивы являются OpenMP и OpenACC.
Синтактические, подобные директивам препроцессора C, таким как C #, также обычно называются «директивами», хотя в этих случаях может не быть никакой реальной фазы предварительной обработки.
Все команды препроцессора начинаются с хэш-символа (#).
История
Директивы датируются ALGOL 68, где они известны как прагматы (от «pragmatic");, и обозначают прагмат или pr; в более новых языках, примечательно C, это было сокращено до «pragma» (нет ‘t');.
Сегодня директивы наиболее известны на языке Си, в начале 1970-х годов, и продолжались через действующий стандарт C99, где они являются либо инструкциями для препроцессора Си, либо, в виде директив для самой компании. Они также в некоторой степени используются в более современных языках, см. ниже.
В некоторых случаях директивы определяют глобальное поведение, в то время как в других случаях они влияют только на локальный раздел, такой как блок программного кода. В некоторых случаях, например в некоторых программах на C, директивы являются необязательными подсказками компилятора и могут игнорироваться, но обычно они предписывают и должны соблюдаться. Однако директива не выполняет никаких действий на самом языке, а только изменяет поведение компилятора.
Этот термин может использоваться для обозначения проприетарных сторонних тегов и команд (или разметки), встроенных в код, которые приводят к дополнительной исполняемой обработке, расширяющей существующие конструкции компилятора, ассемблера и языка, присутствующие в среде разработки. Термин «директива» также применяется по-разному, аналогично термину команда.
Содержание
Препроцессор C
В C и C ++, язык поддерживает простой макрос препроцессор. Исходные строки, которые должны обрабатываться препроцессором, например #определять и #включают упоминаются как директивы препроцессора.
Другая конструкция C, #pragma директива используется для указания компилятору использовать прагматические или зависящие от реализации функции. Двумя известными пользователями этой директивы являются: OpenMP и OpenACC.
Все команды препроцессора начинаются с символа решетки (#).
История
Директивы датируются АЛГОЛ 68, где они известны как прагматики (от «прагматический»), и обозначается прагматик или же пр; в новых языках, особенно в C, это сокращено до «прагма» (без «т»).
Обычно прагматики в АЛГОЛе 68 используются для определения строппинг режим, означающий «как указываются ключевые слова». Далее следуют различные такие директивы, определяющие режимы POINT, UPPER, RES (зарезервировано) или котировки. Обратите внимание на использование строчки для прагматик само ключевое слово (сокращенно пр), либо в режиме POINT, либо в режиме котировки:
В некоторых случаях директивы определяют глобальное поведение, в то время как в других случаях они влияют только на локальный раздел, такой как блок программного кода. В некоторых случаях, например в некоторых программах на C, директивы являются необязательными подсказками компилятора и могут игнорироваться, но обычно они предписывают и должны соблюдаться. Однако директива не выполняет никаких действий на самом языке, а только изменяет поведение компилятора.
Этот термин может использоваться для обозначения проприетарных сторонних тегов и команд (или разметки), встроенных в код, которые приводят к дополнительной исполняемой обработке, расширяющей существующие конструкции компилятора, ассемблера и языка, присутствующие в среде разработки. Термин «директива» также применяется по-разному, аналогично термину команда.
Содержание
Препроцессор C
В C и C ++, язык поддерживает простой макрос препроцессор. Исходные строки, которые должны обрабатываться препроцессором, например #определять и #включают упоминаются как директивы препроцессора.
Другая конструкция C, #pragma директива используется для указания компилятору использовать прагматические или зависящие от реализации функции. Двумя известными пользователями этой директивы являются: OpenMP и OpenACC.
Все команды препроцессора начинаются с символа решетки (#).
История
Директивы датируются АЛГОЛ 68, где они известны как прагматики (от «прагматический»), и обозначается прагматик или же пр; в новых языках, особенно в C, это сокращено до «прагма» (без «т»).
Обычно прагматики в АЛГОЛе 68 используются для определения строппинг режим, означающий «как указываются ключевые слова». Далее следуют различные такие директивы, определяющие режимы POINT, UPPER, RES (зарезервировано) или котировки. Обратите внимание на использование строчки для прагматик само ключевое слово (сокращенно пр), либо в режиме POINT, либо в режиме котировки:
Директивы препроцессора
Препроцессор
Процесс компиляции прошивки очень непростой и имеет несколько этапов, один из первых – работа препроцессора. Препроцессору можно давать команды, которые он выполнит перед компиляцией кода прошивки: это может быть подключение файлов, замена текста, условные конструкции и некоторые другие вещи. Также у препроцессора есть макросы, которые позволяют добавлять в код некоторые интересные вещи.
#include – подключить файл
Также можно указать путь к файлу, который нужно подключить. Например у нас в папке со скетчем есть папка libs, а в ней – файл mylib.h. Чтобы подключить такой файл, пишем:
Компилятор будет искать его в папке со скетчем, в подпапке libs.
#define / undef
Или быстрого и удобного отключения отладки в коде:
Или даже задефайнить целый кусок кода, используя переносы и обратный слэш
Если DEBUG задефайнен, то DEBUG_PRINT – это макро-функция, которая выводит значение в порт. А если не задефайнен – все вызовы DEBUG_PRINT просто убираются из кода и экономят память!
Если DEBUG_ENABLE задефайнен – все вызовы DEBUG() в коде будут заменены на вывод в порт. Если не задефайнен – они будут заменены НИЧЕМ, то есть просто “вырежутся” из кода! Также по DEBUG_ENABLE можно запустить сериал и получить полный контроль над отладкой: если она не нужна – убрали DEBUG_ENABLE и из кода убрался запуск порта и все выводы, что резко сокращает объём занимаемой памяти:
Проблемы
На этом сложности не заканчиваются: #define из одной библиотеки может пролезть в другую библиотеку, которая подключена после первой! Вернёмся к тому же примеру с DarkMagenta – если в моей библиотеке я задефайню это слово и подключу библиотеку до подключения FastLED – я получу ошибку компиляции! Если поменять подключение местами – ошибки не будет. Но, если я захочу использовать DarkMagenta в своём скетче, я буду неприятно удивлён =)
Что я хочу сказать в итоге: #define – гораздо более мощный инструмент, чем может показаться на первый взгляд. Использование define с невнимательным отношением к именам может привести к ошибке, которую будет непросто отловить. Это палка о двух концах: с одной стороны хочется использовать в своей библиотеке define, чтобы никто другой случайно не пролез со своими дефайнами. В то же время, своя библиотека может начать конфликтовать с другими библиотеками. Какой тут выход? Очень простой! Делать имена дефайнов максимально уникальными: если это библиотека – оставлять префикс библиотеки, если это скетч – делать префикс с именем скетча. Также можно отказаться от define в пользу констант или enum, enum кстати удобнее define в плане создания набора констант, а места занимает совсем немного!
#if – условная компиляция
Условная компиляция является весьма мощным инструментом, при помощи которого можно вмешиваться в компиляцию кода и делать его очень универсальным как для пользователя, так и для железа. Рассмотрим директивы условной компиляции:
При помощи условной компиляции можно буквально включать и выключать целые части кода из компиляции, то есть из финальной версии программы, которая будет загружена в микроконтроллер. Рассмотрим несколько конструкция для примера: [fusion_accordion type=”” boxed_mode=”” border_size=”1″ border_color=”” background_color=”” hover_color=”” divider_line=”” title_font_size=”” icon_size=”” icon_color=”” icon_boxed_mode=”” icon_box_color=”” icon_alignment=”” toggle_hover_accent_color=”” hide_on_mobile=”small-visibility,medium-visibility,large-visibility” title=”Пример 1″ open=”no”] [/fusion_toggle][fusion_toggle title=”Пример 2″ open=”no”] [/fusion_toggle][fusion_toggle title=”Пример 3″ open=”no”] [/fusion_toggle][/fusion_accordion]
Сообщения от компилятора
#pragma
Указывает компилятору, что данный файл нужно подключить только один раз. Является более удобной и современной заменой конструкции вида
Такую конструкцию вы можете встретить в 99% библиотек, файлов ядра и вообще заголовочников с кодом.
Конструкция с #pragma pack и #pragma pop позволяет более рационально распределять структуры в памяти. Тема сложная, читайте на Хабре.
Макросы
У препроцессора есть несколько интересных макросов, которыми можно пользоваться в своём коде. Рассмотрим некоторые полезные из них, которые работают на Arduino (точнее, на компиляторе avr-gcc).
__func__ и __FUNCTION__
Макросы __func__ и __FUNCTION__ “возвращают” в виде символьного массива (строки) название функции, внутри которой они вызваны. Являются аналогом друг друга. Например:
__DATE__ и __TIME__
__DATE__ возвращает дату компиляции по системному времени в виде символьного массива (строки) в формате __TIME__ возвращает время компиляции по системному времени в виде символьного массива (строки) в формате ЧЧ:ММ:СС
Работать напрямую с этим макросом очень неудобно, это ведь просто набор символов. У меня есть библиотека buildTime, которая позволяет получать отдельно каждый параметр (день, месяц, год, часы, минуты, секунды). Скачать/почитать можно здесь.
__FILE__ и __BASE_FILE__
__FILE__ и __BASE_FILE__ возвращают полный путь к текущему файлу, опять же как строку. Являются аналогами друг друга.
__LINE__
__LINE__ возвращает номер строки в документе, в которой вызван этот макрос
__COUNTER__
__COUNTER__ возвращает значение, начиная с 0. Значение __COUNTER__ увеличивается на единицу с каждым вызовом макроса в коде.
__COUNTER__ можно использовать для генерации уникальных имён переменных, но об этом мы поговорим когда нибудь в другой раз.