На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила ЧаВо (FAQ) разделов Паскаля
В этом разделе разрешено создавать только темы, в которых описано РЕШЕНИЕ какой-либо общей проблемы, или описание какого-либо аспекта языка Паскаль.
Обсуждение уже созданных тем разрешено, но только конструктивное, например указание на ошибку или уточнение имеющегося текста.

Также читать Требования к оформлению статей
Модераторы: volvo877, Romtek
  
> Директивы транслятора BP7 , Описание часто используемых
    О некоторых полезных директивах компилятора Borland Pascal
    (перевод соответствующих разделов хелпа). Описаны наиболее часто используемые директивы.

    Что такое директивы компилятора.

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

    В том или ином виде директивы компилятора присутствуют практически во всех средах разработки, например, пользователям трансляторов C/C++ хорошо знакомы макросы #include и #define. В среде Borland Pascal 7 директивы компилятора оформляются в виде комментариев специального вида:
    1. начинается директива с обычного символа начала комментария { или (* и следующего непосредственно за ним символа $
    2. сразу за этим символом (без пробелов, табуляций и т.п.) следует имя директивы и ее параметры, например B+
    3. заканчивается директива обычным символом конца комментария }
    Пример: {$A-}

    Внутри одного такого комментария можно записать несколько директив, через запятую: {$A-,B+}

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

    Ниже приведено описание некоторых директив, часто оказывающихся полезными при написании программ:

    Директивы-переключатели

    $B: полное вычисление логических выражений.

    Синтаксис:
    {$B+} – включить полное вычисление логических выражений.
    {$B-} – выключить полное вычисление логических выражений.

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

    Например, в следующем условии:
    ExpandedWrap disabled
      if (i > 12) and (f(i) <> 0) then …;
    при выключенном полном вычислении логических выражений, f(i) <> 0 вычисляться НЕ будет, если i <= 12, т.е., f(i) НЕ будет вызвана, т.к., первого выражения достаточно, чтобы определить значение всего условия.

    Очевидно, если функция f(i) обладает побочным эффектом, т.е., изменяет значение каких-то внешних переменных, и должна быть вызвана в любом случае, такая «оптимизация» может привести к неочевидным, трудно обнаруживаемым ошибкам в программе.

    При включенном полном вычислении логических выражений, выражение f(i) <> 0 будет вычисляться всегда, т.е., f(i) всегда будет выполнена.

    $I: автоматический контроль операций ввода-вывода.

    Синтаксис:
    {$I+} включить автоматический контроль операций ввода-вывода
    {$I-} выключить автоматический контроль операций ввода-вывода

    Назначение:
    Автоматический контроль операций ввода-вывода в Borland Pascal реализован простейшим обработчиком ошибок ввода-вывода, выводящим описание ошибки на экран и корректно завершающим работу программы. Иногда этой функциональности обработчика ошибок недостаточно, и необходимо применять более сложные методы обработки ошибок ввода-вывода, например, обращаться к пользователю за необходимыми указаниями. Для этого, автоматическую обработку ошибок ввода-вывода нужно отключить.

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

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

    Функция IOResult обладает побочным эффектом: сбрасывает признак ошибки ввода-вывода. Т.е., в двух подряд вызовах IOResult только первый вызов вернет признак ошибки.

    Пример использования {$I-} и IOResult:
    ExpandedWrap disabled
      Var
          f : File;
          s : String;
      begin
          repeat
              Write('Введите имя файла (пустая строка – отмена):');
              Readln(s);
              if s = '' then
                  Exit;
              {$I-}
              Assign(f, s);
              Reset(f);
              {$I+}
          until IOResult = 0;
          {Если программа попала в эту точку, файл успешно открыт}
          . . .
      end.


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

    $Q: контроль переполнения.

    Синтаксис:
    {$Q+} – включить контроль переполнения целочисленных операций.
    {$Q-} – выключить контроль переполнения целочисленных операций.

    Назначение:
    Компилятор языка Паскаль способен генерировать код, проверяющий, представим ли результат некоторых целочисленных арифметических операций в рамках типа результата этих операций. Проверяются результаты следующих арифметических операций:
    +, -, *, Abs, Sqr, Succ и Pred.

    Понятие переполнения переменной заданного типа связано с представлением числовых значений в вычислительной технике. Целые числа представляются в виде N-разрядных двоичных записей, и очевидно, не могут принимать более 2N различных значений. Например, тип Integer, представленный 16-разрядной двоичной записью способен принимать 65536 целых значений от –32768 до 32767.

    Переполнение происходит, когда два представимых, например в рамках типа Integer значения в результате применения к ним арифметической операции, дают результат, выходящий за указанный –32768..32767. Простейший пример: 20000*2. Результат 40000 типом Integer представить невозможно. В частности, результат этого умножения, будучи представленным переменной типа Integer, окажется равным –25536.

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

    Кроме того, проверка переполнения существенно замедляет программу, интенсивно выполняющую вычисления с целыми.

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

    Отключение проверки переполнения НЕ отключает проверку деления на 0. Эта ошибка приводит к безусловному завершению работы программы. Контроль переполнения НЕ выполняется для операций Inc и Dec.

    $R: контроль границ.

    Синтаксис:
    {$R+} – включить контроль границ.
    {$R-} – выключить контроль границ.

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

    При включенном контроле границ, во время выполнения следующего кода в программе возникнет ошибка, т.к., индекс 0 недопустим для массива:
    ExpandedWrap disabled
      Var
          a : array[1 .. 10] of integer;
          i : integer;
      begin
          for i := 0 to 10 do a[i] := 0;
          . . .
      end.


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

    $S: контроль стека.

    Синтаксис:
    {$S+} – включить контроль стека.
    {$S-} – выключить контроль стека.

    Назначение:
    Контроль стека представляет собой вид контроля границ, применяемый к стеку – месту где программа и подпрограммы хранят локальные (автоматические) переменные, параметры подпрограмм и адреса возврата, с помощью которых определяют, в какое место вызвавшей программы следует перейти по окончании выполнения подпрограммы.

    Стек в данном случае можно представить себе как пару из массива и указателя последнего использованного элемента этого массива. При вызове подпрограммы выполняются следующие действия:
    1. Начиная с элемента, следующего за последним использованным, в массив помещаются N параметров подпрограммы (занимается еще N элементов массива). Указатель на последний использованный элемент сдвигается на N позиций.
    2. Затем, в массив помещается адрес оператора, следующего в вызывающей программе за вызовом подпрограммы. Указатель последнего использованного элемента сдвигается еще на одну позицию.
    3. Осуществляется переход по адресу начала вызываемой подпрограммы.
    4. Вызванная подпрограмма резервирует M элементов, в которых будет хранить нужные ей переменные. Указатель последнего заполненного элемента сдвигается еще на M позиций.
    5. При возврате из подпрограммы указатель последнего заполненного сдвигается назад на N+1+M позиций.

    Т.к. стек имеет определенный фиксированный размер, очевидно, что при активном использовании стека, при множестве вложенных вызовов подпрограмм, может оказаться, что места в стеке не хватает для размещения параметров или локальных переменных очередной вызванной подпрограммы.

    В такой ситуации говорят, что произошло переполнение стека. В этом случае, при включенном контроле стека, программа аварийно завершается.

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

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

    Параметрические директивы

    $I: подставить текст файла.

    Синтаксис:
    {$I file.inc} – подставить текст файла file.inc.

    Директива по функциональности аналогична директиве #include “file.inc” в языке Си. При ее выполнении, на место конструкции {$I file.inc} подставляется текст файла file.inc.

    Например, имеется два файла:

    const.inc
    ExpandedWrap disabled
      Const
          Pi = 3.14159265;
          Eu = 2.71828183;

    и
    prog.pas
    ExpandedWrap disabled
      program Calc;
      {$I const.inc}
      Var
          r : real;
      begin
          r := Pi/(Eu*5);
          Writeln(“R = ”, r);
      end.


    При трансляции prog.pas const.inc будет «вставлен» в него, и prog.pas будет транслироваться, так, как если бы константы были объявлены в ней самой.

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

    $L: включить в сборку объектный файл.

    Синтаксис:
    {$L file.obj} –включить в сборку file.obj.

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

    В объектных файлах могут содержаться процедуры и функции, объявленные в Паскаль-программе как external (внешние).

    Директива позволяет использовать в программах на паскале код, разработанный на других языках и в других средах разработки.

    $M: размеры стека и кучи

    Синтаксис:
    {$M stacksize, heapmin, heapmax} задать размер стека, минимальный и максимальный объем кучи.

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

    stacksize устанавливает размер стека. Для программ, активно использующих стек, например, с рекурсивными вызовами, может потребоваться увеличение размера стека. Для программ, которые должны занимать как можно меньший объем памяти, напротив, может потребоваться его уменьшение.

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

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

    Директивы условной трансляции

    $DEFINE – определить символ

    Синтаксис:
    {$DEFINE Name}

    Назначение:
    Определяет символ Name, наличие которого можно проверять далее директивами $IFDEF и $IFNDEF

    Пример:
    ExpandedWrap disabled
      {$DEFINE DebugCode}


    $UNDEF – удалить символ

    Синтаксис:
    {$UNDEF Name}

    Назначение:
    Отменяет определение символа, определенного ранее директивой $DEFINE.

    Пример:
    ExpandedWrap disabled
      {$UNDEF DebugCode}


    $IFDEF $ELSE $ENDIF,
    $IFNDEF $ELSE $ENDIF – выполнять трансляцию в зависимости от того, определен ли символ.


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

    Пример:
    ExpandedWrap disabled
      {$DEFINE DebugCode}
      Var
          i : integer;
       
      Procedure CheckAndProcess(I : integer);
      begin
          if i > 12 then Exit;
          Writeln(i*i)
      end;
       
      Procedure Process(I : integer);
      begin
          Writeln(i*i)
      end;
       
      begin
          Readln(i);
          {$IFDEF DebugCode}
              Writeln('I = ', i);
              CheckAndProcess(i);
          {$ELSE}
              Process(i);
          {$ENDIF}
      end.


    Здесь, т.к., определен символ DebugCode, будет транслироваться блок
    ExpandedWrap disabled
              Writeln('I = ', i);
              CheckAndProcess(i);

    а оператор
    ExpandedWrap disabled
              Process(i);

    транслироваться не будет. Чтобы превратить отладочную версию программы в оптимизированную по скорости, достаточно удалить определение символа DebugCode в одном месте – в начале исходного текста.

    $IFOPT $ELSE $ENDIF – проверить значение директивы-переключателя.

    Назначение:
    Позволяет управлять трансляцией участков программы, в зависимости от текущего состояния директивы-переключателя.

    Пример:
    ExpandedWrap disabled
      . . .
      {$IFOPT N-}
          Writeln('Программа должна быть транслирована с поддержкой FPU!');
          Exit;
      {$ELSE}
          A := Ln(ComplexFunc(Z*k, t, c));
      {$ENDIF}
      . . .


    Символы, определенные компилятором

    CPU86 – определен, если выполняется трансляция под процессор, совместимый с ix86
    CPU87 – определен, если в момент трансляции в системе присутствует арифметический сопроцессор
    DPMI – определен, если происходит трансляция под DPMI16 (DOS Protected Mode)
    MSDOS – определен, если происходит трансляция под DOS (DOS Real Mode или DOS Protected Mode)
    WINDOWS – определен, если происходит трансляция под Windows
    VER70 – определен, если транслятор имеет версию 7.0 (Borland/Turbo Pascal 7.0)

    Эти символы можно использовать при в директивах условной компиляции, для того, чтобы генерировать различный код для разных платформ, например, использовать возможность выделения бОльших объемов памяти, чем в Real Mode DOS, при трансляции под DPMI.
    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
    0 пользователей:


    Рейтинг@Mail.ru
    [ Script execution time: 0,0311 ]   [ 16 queries used ]   [ Generated: 6.11.24, 19:56 GMT ]