Difference between revisions of "Conditional compilation/ru"

From Lazarus wiki
Jump to navigationJump to search
 
(8 intermediate revisions by one other user not shown)
Line 5: Line 5:
 
Условная компиляция - это компиляция или пропуск части [[Source_code| исходного кода]] в зависимости от того, существует условие или нет.  
 
Условная компиляция - это компиляция или пропуск части [[Source_code| исходного кода]] в зависимости от того, существует условие или нет.  
  
Функции, которые делают это возможным в большинстве компилируемых языков, называются директивами времени компиляции. Директивы времени компиляции позволяют компилировать блок кода на основе наличия или отсутствия условия во [Compile_time|время компиляции]]. Они являются частью [[Compiler_directive|директив компилятора]].
+
Функции, которые делают это возможным в большинстве компилируемых языков, называются директивами времени компиляции. Директивы времени компиляции позволяют компилировать блок кода на основе наличия или отсутствия условия во [[Compile_time|время компиляции]]. Они являются частью [[Compiler_directive|директив компилятора]].
  
 
Они могут использоваться для различных целей, таких как:  
 
Они могут использоваться для различных целей, таких как:  
Line 27: Line 27:
 
= Директивы в стиле Turbo Pascal =
 
= Директивы в стиле Turbo Pascal =
  
Директивами в стиле Turbo Pascal являются <syntaxhighlight lang="pascal" enclose="none">{$DEFINE}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$ENDIF}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$IFNDEF}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$IFOPT}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$ELSE}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$ELSEIF}</syntaxhighlight> и <syntaxhighlight lang="pascal" enclose="none">{$UNDEF}</syntaxhighlight>.  
+
Директивами в стиле Turbo Pascal являются <syntaxhighlight lang="pascal" inline>{$DEFINE}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$ENDIF}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$IFNDEF}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$IFOPT}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$ELSE}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$ELSEIF}</syntaxhighlight> и <syntaxhighlight lang="pascal" inline>{$UNDEF}</syntaxhighlight>.  
  
 
Мы опишем директивы в контексте стиля. Некоторые определения имеют расширенное значение в другом стиле.  
 
Мы опишем директивы в контексте стиля. Некоторые определения имеют расширенное значение в другом стиле.  
  
Это означает, что в дальнейшем мы можем расширить значение некоторых директив, таких как, например, <syntaxhighlight lang="pascal" enclose="none">{$DEFINE} </syntaxhighlight>, в контексте макросов.
+
Это означает, что в дальнейшем мы можем расширить значение некоторых директив, таких как, например, <syntaxhighlight lang="pascal" inline>{$DEFINE} </syntaxhighlight>, в контексте макросов.
  
 
== $define ==
 
== $define ==
  
Директива <syntaxhighlight lang="pascal" enclose="none">{$DEFINE}</syntaxhighlight> просто объявляет символ, который мы позже можем использовать для условной компиляции:
+
Директива <syntaxhighlight lang="pascal" inline>{$DEFINE}</syntaxhighlight> просто объявляет символ, который мы позже можем использовать для условной компиляции:
  
<syntaxhighlight lang="pascal">{$DEFINE name} //Это задает символ под названием "name"</syntaxhighlight>
+
<syntaxhighlight lang="pascal">{$DEFINE name} //Это объявляет символ под названием "name"</syntaxhighlight>
  
{{Note| вы также можете задать символ из [[Command-line_interface|командной строки]] или , например, <b>-dDEBUG</b> [[IDE]], который будет являться эквивалентом командной строки <syntaxhighlight lang="pascal">{$DEFINE DEBUG}</syntaxhighlight> в исходном коде}}
+
Обратите внимание, что вы также можете объявить символ из [[Command-line_interface|командной строки]] или , например, <b>-dDEBUG</b> [[IDE]], который будет являться эквивалентом командной строки <syntaxhighlight lang="pascal">{$DEFINE DEBUG}</syntaxhighlight> в исходном коде.
  
 
== $undef ==
 
== $undef ==
  
The <syntaxhighlight lang="pascal" enclose="none">{$UNDEF}</syntaxhighlight> directive undefines a previously defined symbol. Here is an example that the author uses in practice:
+
Директива <syntaxhighlight lang="pascal" inline>{$UNDEF}</syntaxhighlight> отменяет объявление ранее определенного символа. Вот пример, который автор использует на практике:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
// Some older source code is polluted with {$IFDEF FPC} that are no
+
// Некоторый старый исходный код, "загрязненый" обилием {$IFDEF FPC}, который больше
// longer necessary depending on the Delphi version to which it it should be compatible.
+
// не нуждается в зависимости от версии Delphi, с которой он должен быть совместим.  
// I always test this by trying this on top of the program or unit:
+
// Я всегда проверяю это, пробуя это поверх программы или модуля:
 
{$IFDEF FPC}
 
{$IFDEF FPC}
 
   {$MODE DELPHI}
 
   {$MODE DELPHI}
 
   {$UNDEF FPC}
 
   {$UNDEF FPC}
 
   {$DEFINE VER150}  
 
   {$DEFINE VER150}  
  // code will now compile as if it was Delphi 7, provided the original Delphi source code was indeed written for Delphi 7 and up.
+
// код теперь будет компилироваться так, как если бы это был Delphi 7, при условии, что исходный код Delphi действительно был написан для Delphi 7 и выше.
 
{$ENDIF}
 
{$ENDIF}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== $ifdef and $endif ==
+
== $ifdef и $endif ==
  
The simplest way to define a block of conditional code is like this:
+
Самый простой способ объявить блок условного кода так:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 66: Line 66:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The above example is quite common for source code that has to compile in both Delphi and Free Pascal
+
Приведенный выше пример довольно распространен для исходного кода, который должен компилироваться как в Delphi, так и в Free Pascal.
  
If the compiler is Delphi then nothing is done, but if the compiler is Free Pascal it will switch Free Pascal to compile and use Delphi syntax mode.
+
Если компилятором является Delphi, то ничего не делается, но если компилятором является Free Pascal, он переключит Free Pascal для компиляции и использования режима синтаксиса Delphi.
  
This "FPC" conditional symbol is defined in system - there is a long list of those.
+
Этот условный символ "FPC" объявлен в системе - там их длинный список. Синтаксис блоков <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight> и <syntaxhighlight lang="pascal" inline>{$ENDIF}</syntaxhighlight> является симметричным: каждый <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight> имеет свой собственный <syntaxhighlight lang="pascal" inline>{$ENDIF}</syntaxhighlight>.  
The <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight> and <syntaxhighlight lang="pascal" enclose="none">{$ENDIF}</syntaxhighlight> block syntax is symmetrical: every <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight> has its own <syntaxhighlight lang="pascal" enclose="none">{$ENDIF}</syntaxhighlight>.
 
  
To help you recognize the corresponding blocks you can use e.g. indentation, but you can also use the [[Comments|comment]] feature:
+
Чтобы помочь вам распознать соответствующие блоки, вы можете использовать, например, отступ, но вы также можете использовать функцию [[Comments|комментариев]]:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
{$IFDEF FPC this part is Free Pascal specific}
+
{$IFDEF FPC эта часть специфична для Free Pascal}
// some Free Pascal specific code
+
// некий Free Pascal специфичный код
{$ENDIF Free Pascal specific code}
+
{$ENDIF Free Pascal специфичный код}
 
</syntaxhighlight>  
 
</syntaxhighlight>  
  
{{Warning| This comment feature is often not well understood. Some people - as on an older version of this wiki entry - assumed you could nest <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight> because the compiler seems to accept the syntax. But the former is false and the latter is true: Yes the compiler accepts the syntax below, but it is not a nested <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight> but a single {<syntaxhighlight lang="pascal" enclose="none">$IFDEF}</syntaxhighlight> condition and the rest is a comment!"
+
{{Warning| Эта особенность комментариев часто не совсем понятна. Некоторые люди - как и в более старой версии этой записи вики - предположили, что вы можете вкладывать <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight>, потому что компилятор, кажется, принимает синтаксис. Но первое неверно, а второе верно: да, компилятор принимает приведенный ниже синтаксис, но это не вложенное <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight>, а одиночное условие <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight>, а остальное - комментарий!  
<br/>
+
 
The code below executes the writeln <b>if and only if red is defined.</b> In this example <syntaxhighlight lang="pascal" enclose="none">{$ifdef blue}</syntaxhighlight> is a comment! Even if the <syntaxhighlight lang="pascal" enclose="none">{$define blue}</syntaxhighlight> is valid.}}
+
Приведенный ниже код выполнит  <i>writeln</i> <b>тогда и только тогда, когда будет объявлен</b> <syntaxhighlight lang="pascal" inline>{$define red}</syntaxhighlight>. В этом примере <syntaxhighlight lang="pascal" inline>{$ifdef blue}</syntaxhighlight> является комментарием! Даже если <syntaxhighlight lang="pascal" inline>{$define blue}</syntaxhighlight> допустим.}}
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
// program completely wrong;
+
// программа формально будет скомпилирована, но полностью неработоспособна
 
{$define blue}   
 
{$define blue}   
 
begin
 
begin
{$ifdef red or $ifdef blue}// everything after red is a comment
+
{$ifdef red or $ifdef blue}// все после red - это комментарий
   writeln ('red or blue'); // this code is never reached
+
   writeln ('red or blue'); // этот код никогда не выполнится
{$endif red or blue}      // everything after $endif is a comment.
+
{$endif red or blue}      // все, что объявлено после $endif, является комментарием.
 
end.</syntaxhighlight>
 
end.</syntaxhighlight>
  
 
== $ifndef ==
 
== $ifndef ==
  
This is the opposite of <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight> and code will be included of a certain condition is <b>not</b> defined. A simple example is:
+
Это противоположно <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight>, и ниже лежащий код выполнится, если объявленное условие <b>не</b> выполняется. Простой пример:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
{$IFNDEF FPC this part not for Free Pascal}
+
{$IFNDEF FPC эта часть не для Free Pascal}
// some specific code that Free Pascal should not compile
+
// некий конкретный код, который Free Pascal не должен компилировать
{$ENDIF code for other compilers than Free Pascal}
+
{$ENDIF код для других компиляторов, кроме Free Pascal}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== $else and $elseif ==
+
== $else и $elseif ==
  
<syntaxhighlight lang="pascal" enclose="none">{$ELSE}</syntaxhighlight> is used to compile code that does not belong to the code block that is defined by the corresponding <syntaxhighlight lang="pascal" enclose="none">{$IFDEF}</syntaxhighlight>. It is also valid in the context <syntaxhighlight lang="pascal" enclose="none">{$IFOPT}</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">{$IF}</syntaxhighlight> or <syntaxhighlight lang="pascal" enclose="none">{$IFC}</syntaxhighlight> that we will discuss later.
+
<syntaxhighlight lang="pascal" inline>{$ELSE}</syntaxhighlight> используется для компиляции кода, который не принадлежит блоку кода, который объявлен соответствующим <syntaxhighlight lang="pascal" inline>{$IFDEF}</syntaxhighlight>. Он также действителен в контексте <syntaxhighlight lang="pascal" inline>{$IFOPT}</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>{$IF}</syntaxhighlight> или <syntaxhighlight lang="pascal" inline>{$IFC}</syntaxhighlight>, которые мы обсудим позже.
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
{$IFDEF red}   
 
{$IFDEF red}   
   writeln('Red is defined');   
+
   writeln('Red объявлен');   
 
{$ELSE  no red}   
 
{$ELSE  no red}   
 
   {$IFDEF blue}   
 
   {$IFDEF blue}   
   writeln('Blue is defined, but red is not defined');   
+
   writeln('Blue объявлен, а red - не объявлен');   
 
   {$ELSE no blue}   
 
   {$ELSE no blue}   
   writeln('Neither red nor blue is defined');  
+
   writeln('Ни red, ни blue не объявлены');  
 
   {$ENDIF blue}   
 
   {$ENDIF blue}   
 
{$ENDIF red}
 
{$ENDIF red}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Such nested conditional written in the above syntax can get very messy and unreadable. Luckily we can simplify it a lot by using <syntaxhighlight lang="pascal" enclose="none">{$ELSEIF}</syntaxhighlight>. The code below is an expanded equivalent of the first example:
+
Такие вложенные условные выражения, написанные в приведенном выше синтаксисе, могут стать очень путанными и нечитаемыми. К счастью, мы можем упростить это, используя <syntaxhighlight lang="pascal" inline>{$ELSEIF}</syntaxhighlight>. Код ниже является расширенным эквивалентом первого примера:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
 
{$IF Defined(red)}   
 
{$IF Defined(red)}   
   writeln('Red is defined');   
+
   writeln('Red объявлен');   
 
{$ELSEIF Defined(blue)}   
 
{$ELSEIF Defined(blue)}   
   writeln('Blue is defined');   
+
   writeln('Blue объявлен');   
 
{$ELSEIF Defined(green)}   
 
{$ELSEIF Defined(green)}   
   writeln('Green is defined');   
+
   writeln('Green объявлен');   
 
{$ELSE}
 
{$ELSE}
   writeln('Neither red, blue or green. Must be black...or something else...');
+
   writeln('Ни red, ни blue, ни green не объявлены. Должен быть black...или что-нибудь еще...');
 
{$ENDIF}
 
{$ENDIF}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
As you can see this is a lot more readable.
+
Как вы можете видеть, это гораздо более читабельно.
  
 
== $ifopt ==
 
== $ifopt ==
  
С помощью <syntaxhighlight lang="pascal" enclose="none">{$IFOPT}</syntaxhighlight> мы можем проверить, задана ли определенная опция компиляции.  
+
С помощью <syntaxhighlight lang="pascal" inline>{$IFOPT}</syntaxhighlight> мы можем проверить, задана ли определенная опция компиляции.  
  
 
Из руководства по программированию:
 
Из руководства по программированию:
  
   <syntaxhighlight lang="pascal" enclose="none">{$IFOPT switch}</syntaxhighlight> скомпилирует текст, который следует за ним, если переключатель switch  
+
   <syntaxhighlight lang="pascal" inline>{$IFOPT switch}</syntaxhighlight> скомпилирует текст, который следует за ним, если переключатель switch  
 
   в данный момент будет находиться в указанном состоянии. Если он не находится в указанном состоянии,  
 
   в данный момент будет находиться в указанном состоянии. Если он не находится в указанном состоянии,  
   то компиляция продолжится после соответствующей директивы <syntaxhighlight lang="pascal" enclose="none">{$ELSE}</syntaxhighlight> или <syntaxhighlight lang="pascal" enclose="none">{$ENDIF}</syntaxhighlight>.
+
   то компиляция продолжится после соответствующей директивы <syntaxhighlight lang="pascal" inline>{$ELSE}</syntaxhighlight> или <syntaxhighlight lang="pascal" inline>{$ENDIF}</syntaxhighlight>.
  
 
Например:
 
Например:
Line 156: Line 155:
 
Скомпилирует оператор Writeln, только если включена генерация информации о типе.  
 
Скомпилирует оператор Writeln, только если включена генерация информации о типе.  
  
{{Note| директива <syntaxhighlight lang="pascal" enclose="none">{$IFOPT}</syntaxhighlight> принимает только короткие опции, т.е. <syntaxhighlight lang="pascal" enclose="none">{$IFOPT TYPEINFO}</syntaxhighlight> не будет принята.}}  
+
{{Note| директива <syntaxhighlight lang="pascal" inline>{$IFOPT}</syntaxhighlight> принимает только короткие опции, т.е. <syntaxhighlight lang="pascal" inline>{$IFOPT TYPEINFO}</syntaxhighlight> не будет принята.}}  
  
 
Обычно этот пример используется для проверки, задан ли режим DEBUG:
 
Обычно этот пример используется для проверки, задан ли режим DEBUG:
Line 184: Line 183:
 
  #ENDIF
 
  #ENDIF
  
= What not to do =
+
= Как не нужно делать =
  
What is wrong with this code? Can you spot it?
+
Что не так с этим кодом? Вы можете это заметить?
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 198: Line 197:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The answer is:
+
Вот ответ:
  
* that Free Pascal compiles for more CPU types than [[32 bit|32]] an [[64 bit|64 bit]], also for e.g. 8 and 16 bit.
+
* Free Pascal компилируется для большего количества типов процессоров, чем [[32 bit|32]] и [[64 bit|64 bit]], например, для 8 и 16 бит.
* on most 64 bit platforms the maximum file size is a [[QWord]], not an [[Int64]].
+
* на большинстве 64-битных платформ максимальный размер файла - это [[QWord]], а не [[Int64]].
  
That programmer fell into a trap that is common: if you use a define, make sure your logic is solid. Otherwise such code can easily cause accidents. The compiler will not catch your logic errors!
+
Этот программист попал в ловушку, которая распространена: если вы используете объявление, убедитесь, что ваша логика надежна. В противном случае такой код может легко вызвать несчастные случаи. Компилятор не будет ловить ваши логические ошибки!  
  
It is always good to realize such things especially that such things can easily be fixed.
+
Всегда хорошо осознавать такие вещи, тем более что такие вещи легко исправить.
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 215: Line 214:
 
     Qword;
 
     Qword;
 
   {$else}
 
   {$else}
     {$error this code is written for win32 or win64}
+
     {$error этот код написан для win32 или win64}
 
   {$endif}
 
   {$endif}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
As an aside of course there is a solution for this particular example that does not use conditionals at all:
+
Помимо этого, есть решение для этого конкретного примера, которое вообще не использует условные выражения:
  
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
Line 226: Line 225:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
What is wrong with this code? Can you spot it?
+
Что не так с этим кодом? Вы можете это заметить?
  
 
<syntaxhighlight lang="pascal">   
 
<syntaxhighlight lang="pascal">   
Line 233: Line 232:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The Answer is:
+
Вот ответ:
  
* Well, I have already wrote a '''comment''' that warned you.. so look at the warning.... You should be able to spot it...
+
* Ну, я уже написал <b>комментарий</b>, который предупредил вас .. так что посмотрите на предупреждение .... Вы должны быть в состоянии определить это ...
* Compiler directives override the compiler... be careful with that axe Eugene.
+
* Директивы компилятора переопределяют компилятор ... будьте осторожны с этим [https://ru.wikipedia.org/wiki/Careful_with_That_Axe,_Eugene топором Юджина].
  
 
{{Template:Directives, Defines and Conditionals}}
 
{{Template:Directives, Defines and Conditionals}}

Latest revision as of 16:14, 6 August 2022

Deutsch (de) English (en) suomi (fi) français (fr) русский (ru)

Что такое условная компиляция?

Условная компиляция - это компиляция или пропуск части исходного кода в зависимости от того, существует условие или нет.

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

Они могут использоваться для различных целей, таких как:

  • изоляция кода для конкретной платформы
  • выбор естественного языка
  • лицензирование частей с открытым и закрытым исходным кодом
  • изоляция экспериментального кода
  • версия компилятора
  • версия библиотеки
  • и т.д. и т.п.

Free Pascal поддерживает четыре различных стиля условной компиляции:

  • Turbo Pascal и ранние директивы стиля Delphi
  • директивы стиля Mac Pascal
  • Современные директивы в стиле Free Pascal и Delphi
  • Макросы времени компиляции
Light bulb  Примечание: здесь синтаксис не чувствителен к регистру, поскольку соответствует всему синтаксису Pascal. Мы будем использовать как строчные, так и прописные примеры. Мы покажем вам разницу между режимами и как их эффективно использовать.

Директивы в стиле Turbo Pascal

Директивами в стиле Turbo Pascal являются {$DEFINE}, {$IFDEF}, {$ENDIF}, {$IFNDEF}, {$IFOPT}, {$ELSE}, {$ELSEIF} и {$UNDEF}.

Мы опишем директивы в контексте стиля. Некоторые определения имеют расширенное значение в другом стиле.

Это означает, что в дальнейшем мы можем расширить значение некоторых директив, таких как, например, {$DEFINE}, в контексте макросов.

$define

Директива {$DEFINE} просто объявляет символ, который мы позже можем использовать для условной компиляции:

{$DEFINE name} //Это объявляет символ под названием "name"

Обратите внимание, что вы также можете объявить символ из командной строки или , например, -dDEBUG IDE, который будет являться эквивалентом командной строки

{$DEFINE DEBUG}

в исходном коде.

$undef

Директива {$UNDEF} отменяет объявление ранее определенного символа. Вот пример, который автор использует на практике:

// Некоторый старый исходный код, "загрязненый" обилием {$IFDEF FPC}, который больше 
// не нуждается в зависимости от версии Delphi, с которой он должен быть совместим. 
// Я всегда проверяю это, пробуя это поверх программы или модуля:
{$IFDEF FPC}
  {$MODE DELPHI}
  {$UNDEF FPC}
  {$DEFINE VER150} 
 // код теперь будет компилироваться так, как если бы это был Delphi 7, при условии, что исходный код Delphi действительно был написан для Delphi 7 и выше.
{$ENDIF}

$ifdef и $endif

Самый простой способ объявить блок условного кода так:

unit cross;
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}

Приведенный выше пример довольно распространен для исходного кода, который должен компилироваться как в Delphi, так и в Free Pascal.

Если компилятором является Delphi, то ничего не делается, но если компилятором является Free Pascal, он переключит Free Pascal для компиляции и использования режима синтаксиса Delphi.

Этот условный символ "FPC" объявлен в системе - там их длинный список. Синтаксис блоков {$IFDEF} и {$ENDIF} является симметричным: каждый {$IFDEF} имеет свой собственный {$ENDIF}.

Чтобы помочь вам распознать соответствующие блоки, вы можете использовать, например, отступ, но вы также можете использовать функцию комментариев:

{$IFDEF FPC эта часть специфична для Free Pascal}
// некий Free Pascal специфичный код
{$ENDIF Free Pascal специфичный код}
Warning-icon.png

Предупреждение: Эта особенность комментариев часто не совсем понятна. Некоторые люди - как и в более старой версии этой записи вики - предположили, что вы можете вкладывать {$IFDEF}, потому что компилятор, кажется, принимает синтаксис. Но первое неверно, а второе верно: да, компилятор принимает приведенный ниже синтаксис, но это не вложенное {$IFDEF}, а одиночное условие {$IFDEF}, а остальное - комментарий! Приведенный ниже код выполнит writeln тогда и только тогда, когда будет объявлен {$define red}. В этом примере {$ifdef blue} является комментарием! Даже если {$define blue} допустим.

// программа формально будет скомпилирована, но полностью неработоспособна
{$define blue}  
begin
{$ifdef red or $ifdef blue}// все после red - это комментарий 
  writeln ('red or blue'); // этот код никогда не выполнится
{$endif red or blue}       // все, что объявлено после $endif, является комментарием.
end.

$ifndef

Это противоположно {$IFDEF}, и ниже лежащий код выполнится, если объявленное условие не выполняется. Простой пример:

{$IFNDEF FPC эта часть не для Free Pascal}
// некий конкретный код, который Free Pascal не должен компилировать
{$ENDIF код для других компиляторов, кроме Free Pascal}

$else и $elseif

{$ELSE} используется для компиляции кода, который не принадлежит блоку кода, который объявлен соответствующим {$IFDEF}. Он также действителен в контексте {$IFOPT}, {$IF} или {$IFC}, которые мы обсудим позже.

{$IFDEF red}  
   writeln('Red объявлен');  
{$ELSE  no red}  
  {$IFDEF blue}  
   writeln('Blue объявлен, а red  - не объявлен');  
  {$ELSE no blue}  
  writeln('Ни red, ни blue не объявлены'); 
  {$ENDIF blue}  
{$ENDIF red}

Такие вложенные условные выражения, написанные в приведенном выше синтаксисе, могут стать очень путанными и нечитаемыми. К счастью, мы можем упростить это, используя {$ELSEIF}. Код ниже является расширенным эквивалентом первого примера:

{$IF Defined(red)}  
  writeln('Red объявлен');  
{$ELSEIF Defined(blue)}  
  writeln('Blue объявлен');  
{$ELSEIF Defined(green)}  
  writeln('Green объявлен');   
{$ELSE}
  writeln('Ни red, ни blue, ни green не объявлены. Должен быть black...или что-нибудь еще...');
{$ENDIF}

Как вы можете видеть, это гораздо более читабельно.

$ifopt

С помощью {$IFOPT} мы можем проверить, задана ли определенная опция компиляции.

Из руководства по программированию:

 {$IFOPT switch} скомпилирует текст, который следует за ним, если переключатель switch 
 в данный момент будет находиться в указанном состоянии. Если он не находится в указанном состоянии, 
 то компиляция продолжится после соответствующей директивы {$ELSE} или {$ENDIF}.

Например:

 {$IFOPT M+}  
   Writeln('Compiled with type information');  
 {$ENDIF}

Скомпилирует оператор Writeln, только если включена генерация информации о типе.

Light bulb  Примечание: директива {$IFOPT} принимает только короткие опции, т.е. {$IFOPT TYPEINFO} не будет принята.

Обычно этот пример используется для проверки, задан ли режим DEBUG:

{$IFOPT D+}{$NOTE debug mode is active}{$ENDIF}

Такие определения также могут находиться в конфигурационных файлах, таких как fpc.cfg, которые также содержат полное объяснение того, как использовать:

# ----------------------
# Defines (preprocessor)
# ----------------------
#
# nested #IFNDEF, #IFDEF, #ENDIF, #ELSE, #DEFINE, #UNDEF are allowed
#
# -d is the same as #DEFINE
# -u is the same as #UNDEF
#
#
# Some examples (for switches see below, and the -? help pages)
#
# Try compiling with the -dRELEASE or -dDEBUG on the command line
#
# For a release compile with optimizes and strip debug info
#IFDEF RELEASE
  -O2
  -Xs
  #WRITE Compiling Release Version
#ENDIF

Как не нужно делать

Что не так с этим кодом? Вы можете это заметить?

var
  MyFilesize:
  {$ifdef Win32} 
    Cardinal 
  {$else}
    int64
  {$endif}

Вот ответ:

  • Free Pascal компилируется для большего количества типов процессоров, чем 32 и 64 bit, например, для 8 и 16 бит.
  • на большинстве 64-битных платформ максимальный размер файла - это QWord, а не Int64.

Этот программист попал в ловушку, которая распространена: если вы используете объявление, убедитесь, что ваша логика надежна. В противном случае такой код может легко вызвать несчастные случаи. Компилятор не будет ловить ваши логические ошибки!

Всегда хорошо осознавать такие вещи, тем более что такие вещи легко исправить.

var
  MyFilesize:
  {$if defined(Win32)} 
    Cardinal 
  {$elseif defined(Win64)}
    Qword;
  {$else}
     {$error этот код написан для win32 или win64}
  {$endif}

Помимо этого, есть решение для этого конкретного примера, которое вообще не использует условные выражения:

var
  MyFilesize:NativeUint;

Что не так с этим кодом? Вы можете это заметить?

  
{$IFDEF BLUE AND $IFDEF RED} Form1.Color := clYellow; {$ENDIF}
{$IFNDEF RED AND $IFNDEF BLUE} Form1.Color := clAqua; {$ENDIF}

Вот ответ:

  • Ну, я уже написал комментарий, который предупредил вас .. так что посмотрите на предупреждение .... Вы должны быть в состоянии определить это ...
  • Директивы компилятора переопределяют компилятор ... будьте осторожны с этим топором Юджина.
Directives, definitions and conditionals definitions
global compiler directives • local compiler directives

Conditional Compiler Options • Conditional compilation • Macros and Conditionals • Platform defines
$IF