11.3 Условная Компиляция
Командная строка компилятора вида
#if выражение
проверяет, является ли результатом вычисления выражения не-ноль. Выражение должно быть константным выражением, котрые обсуждаются в #12. Кроме обычных операций С++ может ипользоваться унарная операция defined. При применении к идетификатору она дает значение не-ноль, если этот идентификатор был ранее определен с помощью #define и после этого не было отмены определения с помощью #undef; иначе ее значение 0. Командная строка вида
#ifdef идентификатор
проверяет, определен ли идентификатор в препроцессоре в данный момент; то есть, был ли он объектом командной строки # define. Командная строка вида
#ifndef идентификатор
проверяет, является ли идентификатор неопределенным в препроцессоре в данный момент.
После каждого из трех видов может стоять произвольное количество строк, возможно, содержащих командную строку
#else
и далее до командной строки
#endif
Если проверенное условие истинно, то все строки между #else и #endif игнорируются. Если проверенное условие ложно, то все строки между проверкой и #else или, в случае отсуттвия #else, #endif, игнорируются.
Эти конструкции могут быть вложенными.
Поделитесь на страничкеСледующая глава >
it.wikireading.ruКомпиляция (программирование) — Компилятор Программа или техническое средство, выполняющее компиляцию.[1][2] Машинная программа, используемая для компиляции.[3][2] Транслятор, выполняющий преобразование программы, составленной на исходном языке, в объектный модуль … Википедия
Сравнение языков программирования — Эту статью следует викифицировать. Пожалуйста, оформите её согласно правилам оформления статей. Условные обозначения … Википедия
Препроцессор Си — Препроцессор С/С++ программный инструмент, изменяющий код программы для последующей компиляции и сборки, используемый в языках программирования Си и его потомка C++. Этот препроцессор обеспечивает использование стандартного набора… … Википедия
Компилятор — Эта статья включает описание термина «Компиляция»; см. также другие значения. Компилятор программа или техническое средство, выполняющее компиляцию.[1][2][3] Компиляция трансляция программы, составленной на исходном языке высокого… … Википедия
Сравнение C Sharp и Java — Правильный заголовок этой статьи Сравнение C# и Java. Он показан некорректно из за технических ограничений. Сравнения языков программирования Общее сравнение Основной синтаксис Основные инструкции Массивы Ассоциативные массивы Операции со… … Википедия
Компиляторы — Компилятор Программа или техническое средство, выполняющее компиляцию.[1][2] Машинная программа, используемая для компиляции.[3][2] Транслятор, выполняющий преобразование программы, составленной на исходном языке, в объектный модуль … Википедия
Кроссплатформенное программное обеспечение — В этой статье не хватает ссылок на источники информации. Информация должна быть проверяема, иначе она может быть поставлена под сомнение и удалена. Вы можете … Википедия
OpenCV — Тип компьютерное зрение Автор … Википедия
Раздувание программного обеспечения — (англ. software bloat, bloatware) тенденция новых программ быть больше по объёму и требовать больше системных ресурсов по сравнению со старыми[источник не указан 267 дней]. Никлаус Вирт в 1996 году написал статью… … Википедия
Оберон-2 — Оберон язык программирования высокого уровня, разработанный Никлаусом Виртом, а также одноимённая операционная система, разработанная Виртом и Юргом Гуткнехтом. Это также родовое имя для всего семейства близкородственных языков, производных от… … Википедия
Как уже было отмечено в статье «Как определить разрядность приложения» в силу разнообразия компиляторов для C++ и отличия их спецификаций конкретного универсального решения вопроса условной компиляции в зависимости от разрядности приложения нет.
Поэтому, рассмотрим два частных случая на примере двух компиляторов из числа наиболее распространённых. Microsoft Visual C++ и C++ Builder.
В этом компиляторе также как и в Delphi имеется символ условной компиляции WIN32.
Однако, при добавлении в проект 64-разрядной конфигурации этот символ оказывается определён и для неё тоже.
Чтобы решить эту проблему достаточно просто на просто удалить символ WIN32 в свойствах 64-разрядной конфигурации. Для этого нужно в свойствах проекта в ветке «Свойства конфигурации»-«C/C++» выбрать «Препроцессор» и в строке «Определения препроцессора» удалить этот символ.
В результате символ WIN32 окажется, определён только для 32-разрядной конфигурации и, тогда можно легко указать, какой код относится к той или иной конфигурации с помощью директивы #if.
#if WIN32 this->Text=»x86″; #else this->Text=»x64″; #endif
#if WIN32 this->Text=»x86″; #else this->Text=»x64″; #endif |
Данный метод, по сути, аналогичен тому, что был рассмотрен ранее на примере Delphi.
В свою очередь для реализации примера рассмотренного ранее для C# достаточно просто добавить определение нового символа для нужной конфигурации (например, для 64-разрядной).
#if WIN32 this->Text=»x86″; #elif WIN64 this->Text=»x64″; #endif
#if WIN32 this->Text=»x86″; #elif WIN64 this->Text=»x64″; #endif |
Также как и в Microsoft Visual C++ в C++ Builder символ условной компиляции WIN32 определён как для 32, так и для 64-разрядной конфигурации. В этом легко убедиться с помощью следующего кода.
#ifdef WIN32 this->Caption = «x86»; #else this->Caption = «x64»; #endif
#ifdef WIN32 this->Caption = «x86»; #else this->Caption = «x64»; #endif |
Однако в отличие от Microsoft Visual C++ возможность удаления этого символа отсутствует.
Проблема решается путём создания собственного символа условной компиляции для заданной конфигурации.
Для этого в свойствах проекта(«Project»-«Options») в ветке «C++ Compiler» нужно выбрать «Directories and Conditionals». После этого выбрать нужную конфигурацию или группу конфигураций («Target») и в строке «Conditional Defines» вписать символ условной компиляции.
В примере на скриншоте ниже показано определение символа W32 для всех 32-разрядных конфигураций. То есть этот символ будет определён как в отладочной, так и в «беловой» конфигурации.
В этом случае можно сразу использовать способ условной компиляции, рассмотренный ранее на примере Delphi.
#ifdef W32 this->Caption = «x86»; #else this->Caption = «x64»; #endif
#ifdef W32 this->Caption = «x86»; #else this->Caption = «x64»; #endif |
А, если проделать аналогичные действия и для 64-разрядной конфигурации, то становится возможным использование метода рассмотренного ранее на примере C#.
#ifdef W32 this->Caption = «x86»; #elif W64 this->Caption = «x64»; #endif
#ifdef W32 this->Caption = «x86»; #elif W64 this->Caption = «x64»; #endif |
В целом возможности Microsoft Visual C++ и C++ Builder в отношении условной компиляции в зависимости от разрядности приложения практически одинаковы. Компилятор от Microsoft, возможно, несколько выигрывает за счёт возможности манипуляции с символом WIN32. В тоже время данное отличие не является принципиальным.
streletzcoder.ru
Компилятор С# csc.exe
и сам язык С# не выставляют никаких предопределенных констант для условной компиляции. VisualStudio
добавляет только значения DEBUG
и TRACE
, которые можно настроить через IDE. IDE также позволяет добавлять ваши собственные произвольные символы, но поскольку они являются по существу фиксированными (инвариантными) значениями, их использование ограничено.
Более мощные настраиваемые параметры могут быть настроены путем ручного редактирования файла проекта .csproj
. Вы можете настроить conditions здесь, чтобы выборочно распространять условные компиляции символов в С# на основе огромного количества информации об окружающей среде и конфигурации, доступной в MSBuild (см. здесь и здесь, но в принципе не может быть полного списка, так как разрозненные компоненты произвольно вносят объявление метаданных -hoc).
Рассмотрим рабочий пример. Один случай, когда полезно скопировать компиляцию, — это если вы хотите написать код, который адаптируется к тем инструментам, которые были обнаружены во время сборки. Таким образом, вы можете использовать новейшие языковые функции, сохраняя при этом возможность компиляции на машинах со старыми инструментами, которые, как ожидается, отклонят синтаксис и/или ключевые слова. Для частного случая С# 7.0 в vs2017
мы можем изменить .csproj
следующим образом:
.csproj файл (выдержка):
Вы также можете идентифицировать каждый из старших компиляторов С#, а также грациозно разлагаться на этом пути. То же самое относится и к обнаружению версии .NET Framework
(из-за запроса в StackOverflow [1]
[2]
[3]
[4]) и любые другие условия окружающей среды. Такими остаются упражнения для читателя, но в случае, если вы хотите скопировать выделенные строки сверху или вставить их, вот текстовая версия. В качестве обновления по скриншоту я добавил одиночные кавычки к условному выражению здесь (хотя все, казалось, работало без них)
<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
В любом случае, теперь вы можете написать условный код С# с помощью #if… #elif… #else… #endif
. Продолжая примерный пример, приведенный ниже код пытается свести к минимуму штрафы за разыменование, используя функцию ref locals, доступную только на С# 7, при замене элементов массива
#if CSHARP7
ref T pi = ref rg[i], pj = ref rg[j];
var t = pi; // swap elements: managed pointers
pi = pj;
pj = t;
#else
var t = rg[i]; // swap elements: clunky
rg[i] = rg[j];
rg[j] = t;
#endif
Обратите внимание, что Visual Studio
IDE выполняет корректно обрабатывает настройки вашего руководства .csproj
во всех отношениях. Учитывая .csproj
, который я показал ранее, редактор кода IDE правильно распознает и оценивает условную компиляцию для целей IntelliSense
, refactoring
, «dimming-out» неактивных блоков кода и т.д.
Я также упомянул, что MSBuild
имеет сокровищницу доступной информации, из которых $(VisualStudioVersion)
был всего лишь одним примером. К сожалению, нетрудно узнать, какие значения доступны и какие значения они могут иметь при времени сборки. Трюк заключается в том, чтобы временно добавить проект C++
в ваше решение Visual Studio
(если у вас его еще нет) вместе с вашим проектом С#. Если вы щелкните правой кнопкой мыши по свойствам проекта для этого .vcxproj
, а затем посмотрите (например) «Дополнительные каталоги Include» на странице C/C++
, выпадающее меню появится в крайнем правом углу, когда вы нажмете на редактирование:
Появится диалоговое окно с кнопкой «Макросы», которую вы можете щелкнуть, чтобы получить список всех доступных переменных MSBuild
плюс их ожидаемые значения в соответствии с платформой и конфигурацией, которые в настоящее время выбраны в среде IDE. Не забудьте поля well-known-item-metadata (с префиксом %
) в нижней части списка.
Вы можете получить представление о том, как много материала находится здесь по размеру большого пальца прокрутки в этом скриншоте. (Они перечислены в алфавитном порядке, я просто прокрутил эту часть раздела «P», потому что у нее была минимальная личная информация). Однако важно отметить, что как переменные (доступные), так и их значения изменяются со временем в ходе сборки, поэтому вы можете найти элементы в этом списке, которые недоступны для вашего .csproj
в момент его обработки.
qaru.site
У меня были проблемы с этими решениями, возможно из-за того, что мои исходные константы были предварительно построены этими свойствами.
<DefineConstants />
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<DebugSymbols>true</DebugSymbols>
Visual Studio 2010 также выдала ошибку из-за полуколоней, утверждая, что они являются незаконными символами. Сообщение об ошибке дало мне подсказку, поскольку я мог видеть предварительно построенные константы, разделенные запятыми, в конце концов последовали за моей «незаконной» точкой с запятой. После некоторого переформатирования и массажа я смог придумать решение, которое работает для меня.
<PropertyGroup>
<!-- Adding a custom constant will auto-magically append a comma and space to the pre-built constants. -->
<!-- Move the comma delimiter to the end of each constant and remove the trailing comma when we're done. -->
<DefineConstants Condition=" !$(DefineConstants.Contains(', NET')) ">$(DefineConstants)$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", "")), </DefineConstants>
<DefineConstants Condition=" $(DefineConstants.Contains(', NET')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(", NET"))))$(TargetFrameworkVersion.Replace("v", "NET").Replace(".", "")), </DefineConstants>
<DefineConstants Condition=" $(TargetFrameworkVersion.Replace('v', '')) >= 2.0 ">$(DefineConstants)NET_20_OR_GREATER, </DefineConstants>
<DefineConstants Condition=" $(TargetFrameworkVersion.Replace('v', '')) >= 3.5 ">$(DefineConstants)NET_35_OR_GREATER</DefineConstants>
<DefineConstants Condition=" $(DefineConstants.EndsWith(', ')) ">$(DefineConstants.Remove($(DefineConstants.LastIndexOf(", "))))</DefineConstants>
</PropertyGroup>
Я бы опубликовал снимок экрана диалогового окна «Дополнительные параметры компилятора» (открывается нажатием кнопки «Расширенные параметры компиляции…» на вкладке «Компиляция» вашего проекта). Но, как новый пользователь, мне не хватает репутации для этого. Если бы вы могли увидеть скриншот, вы увидите, что пользовательские константы будут автоматически заполнены группой свойств, а затем вы будете говорить: «Мне нужно получить часть из них».
РЕДАКТИРОВАТЬ: Получил этот репорт на удивление быстро. Спасибо, ребята! Вот этот снимок экрана:
qaru.site
Компиляция (программирование) — Компилятор Программа или техническое средство, выполняющее компиляцию.[1][2] Машинная программа, используемая для компиляции.[3][2] Транслятор, выполняющий преобразование программы, составленной на исходном языке, в объектный модуль … Википедия
Сравнение языков программирования — Эту статью следует викифицировать. Пожалуйста, оформите её согласно правилам оформления статей. Условные обозначения … Википедия
Препроцессор Си — Препроцессор С/С++ программный инструмент, изменяющий код программы для последующей компиляции и сборки, используемый в языках программирования Си и его потомка C++. Этот препроцессор обеспечивает использование стандартного набора… … Википедия
Компилятор — Эта статья включает описание термина «Компиляция»; см. также другие значения. Компилятор программа или техническое средство, выполняющее компиляцию.[1][2][3] Компиляция трансляция программы, составленной на исходном языке высокого… … Википедия
Сравнение C Sharp и Java — Правильный заголовок этой статьи Сравнение C# и Java. Он показан некорректно из за технических ограничений. Сравнения языков программирования Общее сравнение Основной синтаксис Основные инструкции Массивы Ассоциативные массивы Операции со… … Википедия
Компиляторы — Компилятор Программа или техническое средство, выполняющее компиляцию.[1][2] Машинная программа, используемая для компиляции.[3][2] Транслятор, выполняющий преобразование программы, составленной на исходном языке, в объектный модуль … Википедия
Кроссплатформенное программное обеспечение — В этой статье не хватает ссылок на источники информации. Информация должна быть проверяема, иначе она может быть поставлена под сомнение и удалена. Вы можете … Википедия
OpenCV — Тип компьютерное зрение Автор … Википедия
Раздувание программного обеспечения — (англ. software bloat, bloatware) тенденция новых программ быть больше по объёму и требовать больше системных ресурсов по сравнению со старыми[источник не указан 267 дней]. Никлаус Вирт в 1996 году написал статью… … Википедия
Оберон-2 — Оберон язык программирования высокого уровня, разработанный Никлаусом Виртом, а также одноимённая операционная система, разработанная Виртом и Юргом Гуткнехтом. Это также родовое имя для всего семейства близкородственных языков, производных от… … Википедия
biograf.academic.ru
Мой ответ действителен для препроцессора C, но в соответствии с препроцессором C ++, идентичным препроцессору C? , различия не имеют отношения к этому случаю.
Из справочника C, A, 5-е издание :
Когда функция-макро-вызов активируется, весь макро-вызов заменяется после обработки параметров копией тела. Обработка параметров выполняется следующим образом. Фактические строки токена аргумента связаны с соответствующими формальными именами параметров. Затем создается копия тела, в которой каждое вхождение имени формального параметра заменяется копией фактической последовательности маркеров параметров, связанной с ней. Затем эта копия тела заменяет вызов макроса. […] Как только макровызов был расширен, сканирование макросообщений возобновляется в начале расширения, так что имена макросов могут быть распознаны в рамках расширения с целью дальнейшей замены макросов.
Обратите внимание на слова в расширении . Вот почему ваш пример недействителен. Теперь объедините его с этим: ОБНОВЛЕНИЕ : читайте комментарии ниже.
[…] Макрос вызывается путем записи его имени, левой скобки, а затем после фактической последовательности токенов-аргументов для каждого формального параметра, а затем правой скобки. Фактические последовательности токенов аргументов разделяются запятыми.
В принципе, все это сводится к тому, будет ли препроцессор повторно искать дополнительные макро-вызовы только в рамках предыдущего расширения или если он будет продолжать читать токены, которые появляются даже после расширения.
Это может быть трудно задуматься, но я считаю, что то, что должно произойти с вашим примером, заключается в том, что имя макроса f
распознается во время повторного сканирования, а так как последующая обработка токена показывает вызов макроса для f()
, ваш пример верен и должен выводиться что вы ожидаете. GCC и clang дают правильный результат, и, согласно этим рассуждениям, это также будет действительным (и даст эквивалентные выходы):
#define dds f
#define f(a,b) a+b
dds(eoe,su)
И действительно, выход предварительной обработки в обоих примерах один и тот же. Что касается вывода, который вы получаете с VC ++, я бы сказал, что вы нашли ошибку.
Это согласуется с разделом C99 6.10.3.4, а также с разделом 16.3.4 стандарта C ++, повторным сканированием и последующей заменой :
После того, как все параметры в списке замещения были заменены, а обработка # и ## состоялась, все маркеры предварительной обработки маркеров помещаются. Затем результирующая последовательность токенов предварительной обработки повторно сканируется вместе со всеми последующими токенами предварительной обработки исходного файла для замены других имен макросов.
code-examples.net