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

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

В информатике, препроцессор — это компьютерная программа, принимающая данные на входе, и выдающая данные, предназначенные для входа другой программы, например, такой как компилятор. О данных на выходе препроцессора говорят, что они находятся в препроцессированной форме, пригодной для обработки последующими программами (компилятор). Результат и вид обработки зависят от вида препроцессора; так, некоторые препроцессоры могут только выполнить простую текстовую подстановку, другие способны по возможностям сравниться с языками программирования. Наиболее частый случай использования препроцессора — обработка исходного кода перед передачей его на следующий шаг компиляции. Языки программирования C/C++ и система компьютерной вёрстки PHP является рекурсивным акронимом 'PHP: Hypertext Preprocessor'.

В некоторых языках программирования этап компиляции и трансляции получили название 'препроцессинга'.

Содержание

Лексические препроцессоры

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

Препроцессинг в C/C++

Наиболее широкое распространение среди лексических препроцессоров получил препроцессор языка Си, используемый в языках программирования Си и его потомка, C++. Этот препроцессор обспечивает использование стандартного набора возможностей:

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


Включение

Использование препроцессора Си в наиболее общем виде выглядит в виде

#include "..."

или

#include <...>

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

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

Начиная с 1970-х среди программистов все большее распространение и известность получают более быстрые, безопасные и эффективные альтернативные способы переиспользования подключения файлов, применяемых в большинстве языков программирования: Java и Common Lisp используют пакеты, Паскаль использует юниты (единицы), Modula, Haskell и Python используют модули, а D, разработанный как замена языков Си и C++, использует импорт.

Макросы

Макросы в языке Си преимущественно используются для определения небольших фрагментов кода. Во время обработки кода препроцессором, каждый макрос заменяется соответствующим ему определением. Если макрос имеет параметры, то они указываются в теле макроса; таким образом, макросы языка Си могут походить на Си-функции. Распространенная причина использования — избежание накладных расходов при вызове функции в простейших случаях, когда небольшого кода, вызываемого функцией, достаточно для ощутимого снижения производительности.

Например,

#define max(a,b) ((a) > (b) ? (a) : (b))

определяет макрос max, использующий два аргумента a и b. Этот макрос можно вызывать как любую Си-функцию, используя схожий синтаксис. То есть, после обработки препроцессором,

z = max(x,y);

становится

z = ((x) > (y) ? (x) : (y));

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

Например, если f и g — две функции, вызов

z = max(f(), g());

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

Макросы Си могут походить на функции, создавая новый синтаксис в некоторых пределах, а также могут быть дополнены произвольным текстом (хотя компилятор Си требует, чтобы текст был без ошибок написанным Си-кодом или оформлен как комментарий), но у них есть некоторые ограничения как у программных конструкций. Макросы, схожие с функциями, например, могут быть вызваны как «настоящие» функции, но макрос не может быть передан другой функции при помощи указателя, по той причине, что макрос сам по себе не имеет адреса.

Некоторые современные языки обычно не используют такой способ метапрограммирования с использованием макросов как дополнений строк символов, в расчете или на автоматическое или на ручное подключение функций и методов, а вместо этого другие способы абстракции, такие как шаблоны, общие функции или параметрический полиморфизм. В частности, встраиваемые функции позволяют избежать одного из главных недостатков макросов в современных версия Си и C++, так как встроенная функция обеспечивает преимущество макросов в снижении накладных расходов при вызове функции, но ее адрес можно передавать в указателе для косвенных вызовов или использовать в качестве параметра. Аналогично, проблема множественных вычислений, упомянутая выше в макросе max, для встроенных функций неактуальна.

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

Основная статья: Include guard

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

В общем случае, программисту необходимо использовать конструкцию наподобие этой:

#ifndef FOO_H
#define FOO_H
...(код заголовочного файла)...
#endif

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

Условия препроцессора можно задавать несколькими способами, например:

#ifdef x
...
#else
...
#endif

или

#if x
...
#else
...
#endif

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

Большинство современных языков программирования не используют такие возможности, больше полагаясь на традиционные операторы условия if...then...else..., оставляя компилятору задачу извлечения бесполезного кода из компилируемой программы.

Язык программирования PHP чаще всего используется при обработке веб-страниц. Текст страницы считывается и выдается в неизменном виде. Единственным исключением является наличие в тексте страницы инструкций PHP, ограниченных <?php в начале и ?> в конце.

Вот пример текста страницы, содержащей текущее время:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Текущее время</title>
<head>
<body>
<h1>Текущее время</h1>
<?php
  print strftime('Сейчас %H часов, %M минут %S секунд');
?>
</body>
</html>

Препроцессор PHP заменит выделенную строку на:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Текущее время</title>
<head>
<body>
<h1>Текущее время</h1>
Сейчас 10 часов, 15 минут 20 секунд
</body>
</html>


Прочие лексические препроцессоры

Прочие лексические препроцессоры поддерживают универсальный язык m4, обычно применяемый в кросс-платформенных системах сборки, таких как

Синтаксические препроцессоры

Синтаксические препроцессоры впервые были представлены в семействе языков Лисп. Их роль заключалась в обработке синтаксических деревьев согласно набору правил, определенных пользователем. Для некоторых языков программирования, правила писались на том же самом языке, что и сама программа (симметрия компиляции). Примерами могут служить Лисп и XSLT препроцессор для

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

Модификация синтаксиса

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

Аналогично, набор программ, написанных на


Расширение языка

Отличными примерами расширения языка при помощи макросов может служить их использование в семействе языков программирования Лисп. В то время как эти языки сами по себе имеют простые ядра, ориентированные на динамические типы, стандартные поставки Схема, императивы Common Lisp, объектно-ориентированное программирование ориентированы на статические типы. Почти все эти свойства реализованы синтаксическими препроцессорами, хотя это несет в себе отпечаток этапа компиляции «расширения макросами», управляемой компилятором Лисп. Это все еще может считаться формой препроцессорной обработки, так как это происходит перед остальными этапами компиляции.

Аналогично, типобезопасные регулярные выражения или генерация кода могут быть добавлены в синтаксис и семантику сопрограммы или волокна), монады или прозрачная обработка XML.


Специализированный язык

Одной из необычных особенностей семейства языков Лисп является возможность использования макросов для создания встроенного предметно-ориентированного языка программирования. Обычно, в большом количестве проектов, написанных на языке Лисп, модуль может быть написан на множестве подобных миниязыков, то есть, один может использовать Лисп, а другой может быть написан на диалекте, ориентированном на графический интерфейс пользователя или вывод на принтер и т. д. Стандартная библиотека Common Lisp содержит пример такого уровня синтаксической абстракции в виде макроса LOOP, который реализует Алголоподобные миниязыки для описания комплексной итерации, при сохранении возможности использовать стандартные операторы Лисп.

Препроцессор/язык MetaOCaml обеспечивает схожие возможности и для внешнего предметно-ориентированного языка программирования. Этот препроцессор получая описание семантики языка (т. н. интерпретация) и комбинируя интерпретацию во время компиляции и генерации кода, передает это определение компилятору языка

Макропроцессор общего назначения

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

Макропроцессор m4 вероятно наиболее известный пример подобного макропроцесора общего назначения.

Примеры

  • применение препроцессора Си для препроцессинга Javascript-кода [1].
  • применение M4 (смотри пример в статье) или препроцессора Си [2] в качестве движка шаблонов для генерации imake, интерфейс препроцессор Си, задействованный X Window System, но в настоящее время происходит отказ этого в пользу вычислительной химии), использующий препроцессор Си (или другой препроцессор, определенный вводным файлом) для проверки разметки, применяя преимущественно механизмы
#define

и

#include

для создания эффективной разметки при работе grompp.

Смотри также

Посмотрите «preprocessor» в Викисловаре, свободном словаре.

Дополнительные источники

Ссылки

  1. Как использовать препроцессор Си для JavaScript кода. «JavaScript is Not Industrial Strength» T. Snyder.
  2. Как использовать препроцессор Си в качестве движка шаблонов. «Using a C preprocessor as an HTML authoring tool» J. Korpela, 2000.

Wikimedia Foundation. 2010.

Игры ⚽ Нужно решить контрольную?

Полезное


Смотреть что такое "Условная компиляция" в других словарях:

  • Компиляция (программирование) — Компилятор  Программа или техническое средство, выполняющее компиляцию.[1][2] Машинная программа, используемая для компиляции.[3][2] Транслятор, выполняющий преобразование программы, составленной на исходном языке, в объектный модуль …   Википедия

  • Сравнение языков программирования — Эту статью следует викифицировать. Пожалуйста, оформите её согласно правилам оформления статей.  Условные обозначения  …   Википедия

  • Препроцессор Си — Препроцессор С/С++  программный инструмент, изменяющий код программы для последующей компиляции и сборки, используемый в языках программирования Си и его потомка C++. Этот препроцессор обеспечивает использование стандартного набора… …   Википедия

  • Компилятор — Эта статья включает описание термина «Компиляция»; см. также другие значения. Компилятор  программа или техническое средство, выполняющее компиляцию.[1][2][3] Компиляция  трансляция программы, составленной на исходном языке высокого… …   Википедия

  • Сравнение C Sharp и Java — Правильный заголовок этой статьи  Сравнение C# и Java. Он показан некорректно из за технических ограничений. Сравнения языков программирования Общее сравнение Основной синтаксис Основные инструкции Массивы Ассоциативные массивы Операции со… …   Википедия

  • Компиляторы — Компилятор  Программа или техническое средство, выполняющее компиляцию.[1][2] Машинная программа, используемая для компиляции.[3][2] Транслятор, выполняющий преобразование программы, составленной на исходном языке, в объектный модуль …   Википедия

  • Кроссплатформенное программное обеспечение — В этой статье не хватает ссылок на источники информации. Информация должна быть проверяема, иначе она может быть поставлена под сомнение и удалена. Вы можете …   Википедия

  • OpenCV — Тип компьютерное зрение Автор …   Википедия

  • Раздувание программного обеспечения — (англ. software bloat, bloatware)  тенденция новых программ быть больше по объёму и требовать больше системных ресурсов по сравнению со старыми[источник не указан 267 дней]. Никлаус Вирт в 1996 году написал статью… …   Википедия

  • Оберон-2 — Оберон  язык программирования высокого уровня, разработанный Никлаусом Виртом, а также одноимённая операционная система, разработанная Виртом и Юргом Гуткнехтом. Это также родовое имя для всего семейства близкородственных языков, производных от… …   Википедия


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»