Директивы компилятора в Delphi


Директивы компилятора — Версии Delphi

У меня есть блок, который я написал в Delphi 7 некоторое время назад, и просто получил удовольствие (боль) от преобразования в Delphi XE (Unicode).

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

У меня только Delphi 7 и Delphi XE, но из того, что я собираю, код, написанный в Delphi 1, Delphi 2007 будет компилироваться, но код из Delphi 2009 и выше будет Unicode.

. В любом случае, в модуле я разделяю un-unicode и unicode так:

Как изменить директиву компилятора, чтобы правила применялись к нескольким версиям? Например, что-то вроде:

Затем это будет охватывать все версии Delphi, если я буду распространять источник или блок .dcu.

Интересно, является ли самый простой подход в этом случае переключать поведение на UNICODE условном. Это условие определено тогда и только тогда, когда вы используете Unicode-версию Delphi, то есть в Delphi 2009 и более поздних версиях. Большим преимуществом этого является то, что это будущее доказательство — вам не нужно обновлять свой код каждый раз, когда выпускается новый Delphi. Более того, условный переключатель будет гораздо читабельнее, поскольку он четко выражает намерение.

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

Директивы компилятора — Версии Delphi

У меня есть блок, который я написал в Delphi 7 некоторое время назад, и просто получил удовольствие (боль) от преобразования в Delphi XE (Unicode).

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

У меня только Delphi 7 и Delphi XE, но из того, что я собираю, код, написанный в Delphi 1, Delphi 2007 будет компилироваться, но код из Delphi 2009 и выше будет Unicode.

. Во всяком случае, в блоке я отделяющий не-Юникод и Юникод, как так:

Как изменить директиву компилятора поэтому правила применяются к Многоязычным версиям? Например, что-то вроде:

Это будет охватывать все версии Delphi, если я буду распространять источник или блок .dcu.

Создан 25 ноя. 11 2011-11-25 14:07:16 Anonymous

2 ответа

Интересно, является ли самый простой подход в этом случае переключать поведение на UNICODE условно. Это условие определено тогда и только тогда, когда вы используете Unicode-версию Delphi, то есть в Delphi 2009 и более поздних версиях. Большим преимуществом этого является то, что это будущее доказательство — вам не нужно обновлять свой код каждый раз, когда выпускается новый Delphi. Более того, условный переключатель будет гораздо читабельнее, поскольку он четко выражает намерение.

Документация Delphi имеет отличный topic, содержащий все предопределенные условные обозначения. Полный список условных обозначений версии также linked оттуда.

Создан 25 ноя. 11 2011-11-25 14:20:45 David Heffernan

+1, вы были быстрее. Если OP хочет только разделить код на Unicode-версию Delphi, то директива ‘UNICODE’ является точной. Существуют также CompilerVersion и RTLVersion для определения текущей версии Delphi. – TLama 25 ноя. 11 2011-11-25 14:31:10

. если кто-то использовал «UNICODE» в прошлом. Например, чтобы удовлетворить отсутствие поддержки Unicode в самой Delphi;) . все еще, +1 . ваше решение кажется более чистым, если можно гарантировать, что ‘UNICODE’ еще не используется. – 0xC0000022L 25 ноя. 11 2011-11-25 14:33:44

@STATUS_ACCESS_DENIED В этом случае необходимо изменить код, который определяет и использует пользовательский условный символ с именем UNICODE. – David Heffernan 25 ноя. 11 2011-11-25 14:36:29

@ Давид: Я не уверен, что согласен. В C/C++ для определенных объектов (определений и функций) было принято, чтобы они начинались с двух ведущих подчеркиваний, если они специфичны для компилятора. Borland (et al.) Должен был бы сделать такие правила давно. Они меняют правила и постоянно нарушают код. В частности, поддержка Unicode/была бесполезной в этом отношении. Я до сих пор не понимаю, как совершенные дельфийцы могут оставаться такими спокойными;) . Я некоторое время оставил все это позади меня, хотя по-прежнему пользуюсь Delphi. – 0xC0000022L 25 ноя. 11 2011-11-25 14:53:46

@STATUS Как бы то ни было, это то, что есть, и если Emba определит ‘UNICODE’, тогда вам не нужно, нравится вам это или нет. – David Heffernan 25 ноя. 11 2011-11-25 14:54:52

@ Давид спасибо за информацию, используя директиву UNICODE намного лучше :)user741875 25 ноя. 11 2011-11-25 15:09:07

Ваш лучший выбор — это посмотреть на один из многих проектов JEDI, например, http://sourceforge.net/projects/jedi-apilib/ и посмотреть, как они это делают. У них есть общие файлы, содержащие именно те детали, которые вас интересуют. JVCL — еще один хороший выбор .

Создан 25 ноя. 11 2011-11-25 14:11:10 0xC0000022L

Да jvcl inc совершенен. Существует только каждая директива компилятора для кодирования некоторых разделов, относящихся к конкретным версиям. – az01 25 ноя. 11 2011-11-25 14:18:50

Удаление директив компилятора Delphi IFDEf автоматически

В настоящее время я работаю с «унаследованным» кодом, который (разбросан случайным образом) по целому ряду условных директив компилятора, основанных на версии Delphi, возвращаясь к Delphi 2. Отныне вся разработка будет с Delphi 2009 или в будущем. Есть ли в Delphi 2009 инструмент или плагин, который автоматически удаляет сегменты условного кода компилятора на основе указанной «минимальной» версии?

5 ответов

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

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

Функциональность условных определений особенно полезна, поскольку вы можете просто удалить все такие условные выражения или предоставить набор DEFINE, которые вы хотите применить. DIPP затем выдаст исходный файл, который отражает то, как он будет выглядеть для компилятора с этими символами DEFINED, но без самих условных директив.

Таким образом, в вашем случае вы просто определили символы, соответствующие вашей базовой версии Delphi.

Вы должны дать JEDI PreProcessor (Pascal PreProcessor) в JCL попытка

В сундуке в нашем SVN источник можно найти в директории jCL/DevTools/JPP и в нашем последнем выпуске (2.1) zip-файл jpp.exe можно найти в dir devtools.

Мой совет — ТОЛЬКО изменить код, которым вы полностью управляете. Однако, если вы также собираетесь изменить существующий сторонний код, я предлагаю вам пройти через каждый IFDEF, определенный для проверки. Некоторые поставщики не используют стандартные вызовы IFDEF VERxxx, но создают свои собственные, которые могут называться чем-то вроде VER70UP или чего-то подобного. Наиболее распространенным местом для этого могут быть включаемые файлы, поэтому ищите файл <$ I . INC>в начале каждого файла, а затем анализируйте его на предмет того, что и как используется.

Другой причиной для анализа каждого $ DEFINE/$ UNDEF является тот факт, что для конкретной версии может быть включено новое определение, которое вы ранее не проверяли. которое в конечном итоге приводит к мертвому коду.

Я не знаю такого инструмента, но его было бы относительно просто написать.

  1. Перебрать все файлы в каталоге, используя FindFirst а также FindNext
  2. использование TStringList.LoadFromFile читать все файлы PAS.
  3. Перебрать строки и искать <$IfDef>директивы. Если версия, указанная в условном разделе, старше, чем D2009, удалите весь текст до <$EndIf>.
  4. использование TStringList.SaveToFile записать измененный файл на диск.

использование GExperts, вы можете использовать GrepSearch или GrepRegularExpressions для поиска в вашем коде, а затем использовать инструмент Replace в GrepResults, чтобы удалить все, что вам нужно.

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

Директивы по версиям компилятора Delphi: <$ IFDEF VER180>— 2020

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

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

Предположим, вы пишете свой собственный (коммерческий) пользовательский компонент. Пользователи вашего компонента могут иметь разные версии Delphi, чем у вас.

Если они попытаются перекомпилировать код компонента (ваш код) — у них могут быть проблемы! Что если вы использовали параметры по умолчанию в ваших функциях, а у пользователя Delphi 3?

Директива компилятора: $ IfDef

Директивы компилятора — это специальные синтаксические комментарии, которые мы можем использовать для управления функциями компилятора Delphi. Компилятор Delphi имеет три типа директив: переключение директив, директивы параметров а также условные директивы, Условная компиляция позволяет нам выборочно компилировать части исходного кода в зависимости от того, какие условия установлены.

Директива компилятора $ IfDef запускает секцию условной компиляции.

Синтаксис выглядит так:

DefName представляет так называемый условный символ. Delphi определяет несколько стандартных условных символов. В приведенном выше «коде», если определено DefName, код выше $ Else компилируется.

Delphi Version Symbols

Распространенным применением директивы $ IfDef является тестирование версии компилятора Delphi.

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

  • УСЛОВНОЕ ОБОЗНАЧЕНИЕ — Компиляционная версия
  • VER80 — Delphi 1
  • VER90 — Delphi 2
  • VER100 — Delphi 3
  • VER120 — Delphi 4
  • VER130 — Delphi 5
  • VER140 — Delphi 6
  • VER150 — Delphi 7
  • VER160 — Delphi 8
  • VER170 — Delphi 2005
  • VER180 — Delphi 2006

  • VER180 — Delphi 2007
  • VER185 — Delphi 2007
  • VER200 — Delphi 2009
  • VER210 — Delphi 2010
  • VER220 — Delphi XE
  • VER230 — Delphi XE2
  • WIN32 — Указывает, что операционной средой является Win32 API.
  • LINUX — Указывает, что операционной средой является Linux
  • MSWindows — Указывает, что операционной средой является MS Windows / li]
  • ПРИСТАВКА — Указывает, что приложение компилируется как консольное приложение.

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

Примечание: символ VER185, например, используется для обозначения компилятора Delphi 2007 или более ранней версии.

Использование символов «VER»

Обычно (и желательно) для каждой новой версии Delphi добавлять несколько новых подпрограмм RTL к языку.

Например, функция IncludeTrailingBackslash, представленная в Delphi 5, добавляет «» в конец строки, если ее там еще нет. В проекте Delphi MP3 я использовал эту функцию, и несколько читателей пожаловались, что не могут скомпилировать проект — у них есть какая-то версия Delphi до Delphi 5.

Одним из способов решения этой проблемы является создание собственной версии этой подпрограммы — функции AddLastBackSlash.

Если проект должен быть скомпилирован на Delphi 5, вызывается IncludeTrailingBackslash. Если используются некоторые из предыдущих версий Delphi, мы моделируем функцию IncludeTrailingBackslash.

Это может выглядеть примерно так:

функция AddLastBackSlash (ул: строка) : строка; начать Результат: = IncludeTrailingBackslash (str); если Copy (str, Length (str), 1) = «» затем Результат: = ул еще Результат: = str + «»; конец;

При вызове функции AddLastBackSlash Delphi выясняет, какая часть функции должна использоваться, а другая часть просто пропускается.

Delphi 2008?

Delphi 2007 использует VER180 для обеспечения неразрывной совместимости с Delphi 2006, а затем добавляет VER185 для разработки, которая по каким-либо причинам должна быть нацелена на Delphi 2007.

Примечание. Каждый раз, когда интерфейс модуля изменяет код, использующий этот модуль, его необходимо перекомпилировать.Delphi 2007 — выпуск без прерываний, означающий, что файлы DCU из Delphi 2006 будут работать как есть.

Директивы компилятора в Delphi

Как сделать свои собственные сообщения при компилляции

Как узнать версию компиллятора ?

Какие есть директивы компилятора?

<$I+>и <$I->— директивы контроля ввода/вывода
<$M>и <$S>— директивы, определяющие размер стека

<$M+>и <$M->— директивы информации времени выполнения о типах
<$Q+>и <$Q->— директивы проверки переполнения целочисленных операций

<$R>— директива связывания ресурсов

<$R+>и <$R->— директивы проверки диапазона

<$APPTYPE CONSOLE>— директива создания консольного приложения

1) Директивы компилятора, разрешающие или запрещающие проверку утверждений.

По умолчанию <$C+>или <$ASSERTIONS ON>
Область действия локальная

Директивы компилятора $C разрешают или запрещают проверку утверждений. Они влияют на работу процедуры Assert,используемой при отладке программ. По умолчанию действует
директива <$C+>и процедура Assert генерирует исключение EAssertionFailed , если проверяемое утверждение ложно.
Так как эти проверки используются только в процессе отладки программы, то перед ее окончательной компиляцией следует указать директиву <$C->. При этом работа процедур Assert будет блокировано и генерация исключений EassertionFailed производиться не будет.
Директивы действуют на весь файл исходного кода независимо от того, в каком месте файла они расположены.

2) Директивы компилятора, включающие и выключающие контроль файлового ввода-вывода.

По умолчанию <$I+>или <$IOCHECKS ON>
Область действия локальная

Директивы компилятора $I включают или выключают автоматический контроль результата вызова процедур ввода-вывода Object Pascal . Если действует директива <$I+>, то при возвращении процедурой ввода-вывода ненулевого значения генерируется исключение EInOutError и в его свойство errorcode заносится код ошибки. Таким образом, при действующей директиве <$I+>операции ввода-вывода располагаются в блоке try . except , имеющем обработчик исключения EInOutError . Если такого блока нет, то обработка производится методом TApplication.HandleException .
Если действует директива <$I->, то исключение не генерируется. В этом случае проверить, была ли ошибка, или ее не было, можно, обратившись к функции IOResult . Эта функция очищает ошибку и возвращает ее код, который затем можно анализировать. Типичное применение директивы <$I->и функции IOResult демонстрирует следующий пример:

AssignFile ( F,s );
Rewrite (F);

<$I+>
i:=IOResult ;
if i <> 0 then
case i of
2 : .
3 : .
end ;

В этом примере на время открытия файла отключается проверка ошибок ввода вывода, затем она опять включается, переменной i присваивается значение, возвращаемое функцией IOResult и, если это значение не равно нулю (есть ошибка), то предпринимаются какие-то действия в зависимости от кода ошибки. Подобный стиль программирования был типичен до введения в Object Pascal механизма обработки исключений. Однако сейчас, по-видимому, подобный стиль устарел и применение директив $I потеряло былое значение.

3) Директивы компилятора, определяющие размер стека

По умолчанию <$M 16384,1048576>
Область действия глобальная

Локальные переменные в процедурах и функциях размещаются в стеке приложения. При каждом вызове процедуры или функции ее локальные переменные помещаются в стек. При выходе из процедуры или функции эти локальные процедуры удаляются из стека.
Директивы компилятора $M задают параметры стека приложения: его минимальный и максимальный размеры. Приложение всегда гарантировано имеет размер стека, равный его минимальной величине. Если при запуске приложения Windows обнаруживает, что не может выделить этот минимальный объем памяти, то выдается сообщение об этой ошибке.
Если во время работы выясняется, что минимального размера стека не хватает, то размер увеличивается на 4 K, но не более, чем до установленного директивой максимального размера. Если увеличение размера стека невозможно из-за нехватки памяти или из-за достижения его максимальной величины, генерируется исключение EStackOverflow . Минимальный размер стека по умолчанию равен 16384 (16K). Этот размер может изменяться параметром minstacksize директивы <$M>или параметром number директивы <$MINSTACKSIZE>.
Максимальный размер стека по умолчанию равен 1,048,576 (1M). Этот размер может изменяться параметром maxstacksize директивы <$M>или параметром number директивы <$MAXSTACKSIZE number >. Значение минимального размера стека может задаваться целым числом в диапазоне между1024 и 2147483647. Значение максимального размера стека должно быть не менее минимального размера и не более 2147483647. Директивы задания размера стека могут включаться только в программу и не должны использоваться в библиотеках и модулях.

В Delphi 1 имеется процедура компилятора <$S>, осуществляющая переключение контроля переполнения стека. Теперь этот процесс полностью автоматизирован и директива <$S>оставлена только для обратной совместимости.

4) Директивы компилятора, включающие и выключающие генерацию информации времени выполнения о типах ( runtime type information — RTTI).

По умолчанию <$M->или <$ TYPEINFO OFF>
Область действия локальная

Директивы компилятора $M включают или выключают генерацию информации времени выполнения о типах ( runtime type information — RTTI). Если класс объявляется в состоянии <$M+>или является производным от класса объявленного в этом состоянии, то компилятор генерирует RTTI о его полях, методах и свойствах, объявленных в разделе published . В противном случае раздел published в классе не допускается. Класс TPersistent , являющийся предшественником большинства классов Delphi и все классов компонентов, объявлен в модуле Classes в состоянии <$M+>. Так что для всех классов, производных от него, заботиться о директиве <$M+>не приходится.

5) Директивы компилятора, включающие и выключающие проверку переполнения при целочисленных операциях

По умолчанию <$Q->или <$OVERFLOWCHECKS OFF>
Область действия локальная

Директивы компилятора $Q включают или выключают проверку переполнения при целочисленных операциях. Под переполнением понимается получение результата, который не может сохраняться в регистре компьютера. При включенной директиве <$Q+>проверяется переполнение при целочисленных операциях +, -, *, Abs , Sqr , Succ , Pred , Inc и Dec . После каждой из этих операций размещается код, осуществляющий соответствующую проверку. Если обнаружено переполнение, то генерируется исключение EIntOverflow . Если это исключение не может быть обработано, выполнение программы завершается.
Директивы $Q проверяют только результат арифметических операций. Обычно они используются совместно с директивами <$R>, проверяющими диапазон значений при присваивании.
Директива <$Q+>замедляет выполнение программы и увеличивает ее размер. Поэтому обычно она используется только во время отладки программы. Однако, надо отдавать себе отчет, что отключение этой директивы приведет к появлению ошибочных результатов расчета в случаях, если переполнение действительно произойдет во время выполнении программы. Причем сообщений о подобных ошибках не будет.

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

По умолчанию <$R>или <$RANGECHECKS OFF>
Область действия локальная

Директивы компилятора $R включают или выключают проверку диапазона целочисленных значений и индексов. Если включена директива <$R+>, то все индексы массивов и строк и все присваивания скалярным переменным и переменным с ограниченным диапазоном значений проверяются на соответствие значения допустимому диапазону. Если требования диапазона нарушены или присваиваемое значение слишком велико, генерируется исключение ERangeError . Если оно не может быть перехвачено, выполнение программы завершается.
Проверка диапазона длинных строк типа Long strings не производится.
Директива <$R+>замедляет работу приложения и увеличивает его размер. Поэтому она обычно используется только во время отладки.

6) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Директива компилятора <$R>указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows . По умолчанию расширение файлов ресурсов — .RES.
В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах <$R>, копируются в выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву <$R>, а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories / Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.
При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл . pas директиву <$R *.DFM>, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и генерируется исключение EResNotFound .


Все установленные в настройках опции компиляции можно вставить непосредственно в текст программы нажав клавиши Ctrl-O , O

Как сделать свои собственные сообщения при компилляции ?

destructor TumbSelectionTempTable.Destroy ;
begin
// Clear the temp tables.
<$MESSAGE Warn ' - remember to free all allocated objects'>
ClearAllOuterWorldFold ;
if FSubjectsTempTableCreated then
DropTempTable ( FTableName );

FOuterWorldsFolded.Free ;
FQuery.Free ;
inherited ;
end ;

Работает только в Дельфи 6/7

Как узнать версию компилятора?

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

В Дельфи предопределены специальные константы компиляции для этого:

Ver80 — Дельфи 1
Ver90 — Дельфи 2
Ver93 — С Buider 1
Ver100 — Дельфи 3
Ver110 — С Buider 3
Ver120 — Дельфи 4
Ver125 — С Buider 4
Ver130 — Дельфи 5
Ver140 — Дельфи 6
Ver150 — Дельфи 7

procedure TForm1.Button2Click( Sender : TObject );
const Version=

Директива компилятора Delphi для оценки аргументов в обратном порядке — delphi

Я был очень впечатлен этим delphi двумя лайнерами, используя функцию IFThen из Math.pas. Однако сначала он оценивает DB.ReturnFieldI, что является неудачным, потому что мне нужно вызвать DB.first, чтобы получить первую запись.

(как бессмысленное разъяснение, потому что у меня уже есть много хороших ответов. Я забыл упомянуть, что 0 — это код, который DB.First возвращает, если он что-то получил в нем, возможно, не имел смысла в противном случае)


Очевидно, это не такая уж большая проблема, как я мог бы заставить ее работать с пятью прочными лайнерами. Но все, что мне нужно для этого, — это использовать Delphi для оценки DB.first сначала и DB.ReturnFieldI. Я не хочу менять math.pas, и я не думаю, что это гарантирует мне перегрузку, потому что там, как 16 функций.

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

    5 4
  • 19 окт 2020 2020-10-19 15:25:35
  • Peter Turner

4 ответа

AFAIK нет директивы компилятора для управления этим. Если вы не используете соглашения stdcall/cdecl/safecall, параметры передаются слева направо в стеке, но поскольку соглашение по регистру по умолчанию может также передавать параметры в регистрах, может случиться так, что параметр будет вычисляться позже поместить в регистр перед вызовом. И поскольку только фиксированный порядок фиксирован (EAX, EDX, ECX) для параметров, которые соответствуют критериям, регистры могут быть загружены в любом порядке. Вы могли бы попытаться принудительно использовать соглашение о вызове «pascal» (в любом случае вам нужно будет переписать функцию), но IMHO всегда опасно полагаться на такой код, если компилятор не может явно гарантировать порядок оценки. И введение порядка оценки может значительно уменьшить количество доступных оптимизаций.

  • 19 окт 2020 2020-10-19 15:25:36
  • [email protected]

Не можете ли вы изменить свой запрос, чтобы иметь только один результат, чтобы избежать команды «Первый»? Также как:

  • 19 окт 2020 2020-10-19 15:25:36
  • philnext

соглашение о вызове влияет на способ их оценки.
Для этого не существует компилятора.

Pascal — это вызов, который вы должны использовать для получения этого поведения.

Хотя я лично никогда не буду зависеть от этого типа поведения.

В следующей примерной программе показано, как это работает.

Это потребует от вас написать свои собственные функции IfThen.

Если вы действительно хотите, чтобы это был один лайнер, вы действительно можете это сделать в Delphi. Я просто думаю, что это выглядит уродливо.

  • 19 окт 2020 2020-10-19 15:25:36
  • Robert Love

Обычно порядок оценки выражений undefined. (C и С++ аналогичны. Java всегда оценивает слева направо.) Компилятор не контролирует его. Если вам нужно два выражения для оценки в определенном порядке, напишите свой код по-разному. Я бы не стал беспокоиться о количестве строк кода. Линии дешевы; используйте столько, сколько вам нужно. Если вы часто используете этот шаблон, напишите функцию, которая завершает все:

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

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

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

Соглашение о вызове pascal передает аргументы слева направо в стеке. Это означает, что самый левый аргумент находится в нижней части стека, а самый правый аргумент находится вверху, чуть ниже адреса возврата. Если функция IfThen использовала этот вызов, существует несколько способов, которыми компилятор мог бы достичь этого макета стека:

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

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

Сначала выделите пространство стека и оцените в любом порядке:

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

Соглашение о вызове по умолчанию также передает аргументы слева направо, но первые три аргумента, которые соответствуют, передаются в регистры. Однако регистры, используемые для передачи аргументов, также являются реестрами, наиболее часто используемыми для оценки промежуточных выражений. Результат DB.First = 0 необходимо было передать в регистр EAX, но компилятор также нуждался в этом регистре для вызова ReturnFieldI и для вызова First . Вероятно, было бы гораздо удобнее сначала оценить вторую функцию, например:

Еще одно замечание: ваш первый аргумент является составным выражением. Там вызов функции и сравнение. Там нечего гарантировать, что эти две части выполняются последовательно. Компилятор может сначала вызвать вызовы функций, вызвав First и ReturnFieldI , а затем сравните возвращаемое значение First с нулем.

Директивы компилятора — Версии Delphi

У меня есть блок, который я написал в Delphi 7 некоторое время назад, и просто получил удовольствие (боль) от преобразования в Delphi XE (Unicode).

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

У меня только Delphi 7 и Delphi XE, но из того, что я собираю, код, написанный в Delphi 1, Delphi 2007 будет компилироваться, но код из Delphi 2009 и выше будет Unicode.

. Во всяком случае, в блоке я отделяющий не-Юникод и Юникод, как так:

Как изменить директиву компилятора поэтому правила применяются к Многоязычным версиям? Например, что-то вроде:

Это будет охватывать все версии Delphi, если я буду распространять источник или блок .dcu.

Создан 25 ноя. 11 2011-11-25 14:07:16 Anonymous

2 ответа

Интересно, является ли самый простой подход в этом случае переключать поведение на UNICODE условно. Это условие определено тогда и только тогда, когда вы используете Unicode-версию Delphi, то есть в Delphi 2009 и более поздних версиях. Большим преимуществом этого является то, что это будущее доказательство — вам не нужно обновлять свой код каждый раз, когда выпускается новый Delphi. Более того, условный переключатель будет гораздо читабельнее, поскольку он четко выражает намерение.

Документация Delphi имеет отличный topic, содержащий все предопределенные условные обозначения. Полный список условных обозначений версии также linked оттуда.

Создан 25 ноя. 11 2011-11-25 14:20:45 David Heffernan

+1, вы были быстрее. Если OP хочет только разделить код на Unicode-версию Delphi, то директива ‘UNICODE’ является точной. Существуют также CompilerVersion и RTLVersion для определения текущей версии Delphi. – TLama 25 ноя. 11 2011-11-25 14:31:10

. если кто-то использовал «UNICODE» в прошлом. Например, чтобы удовлетворить отсутствие поддержки Unicode в самой Delphi;) . все еще, +1 . ваше решение кажется более чистым, если можно гарантировать, что ‘UNICODE’ еще не используется. – 0xC0000022L 25 ноя. 11 2011-11-25 14:33:44

@STATUS_ACCESS_DENIED В этом случае необходимо изменить код, который определяет и использует пользовательский условный символ с именем UNICODE. – David Heffernan 25 ноя. 11 2011-11-25 14:36:29

@ Давид: Я не уверен, что согласен. В C/C++ для определенных объектов (определений и функций) было принято, чтобы они начинались с двух ведущих подчеркиваний, если они специфичны для компилятора. Borland (et al.) Должен был бы сделать такие правила давно. Они меняют правила и постоянно нарушают код. В частности, поддержка Unicode/была бесполезной в этом отношении. Я до сих пор не понимаю, как совершенные дельфийцы могут оставаться такими спокойными;) . Я некоторое время оставил все это позади меня, хотя по-прежнему пользуюсь Delphi. – 0xC0000022L 25 ноя. 11 2011-11-25 14:53:46

@STATUS Как бы то ни было, это то, что есть, и если Emba определит ‘UNICODE’, тогда вам не нужно, нравится вам это или нет. – David Heffernan 25 ноя. 11 2011-11-25 14:54:52

@ Давид спасибо за информацию, используя директиву UNICODE намного лучше :)user741875 25 ноя. 11 2011-11-25 15:09:07

Ваш лучший выбор — это посмотреть на один из многих проектов JEDI, например, http://sourceforge.net/projects/jedi-apilib/ и посмотреть, как они это делают. У них есть общие файлы, содержащие именно те детали, которые вас интересуют. JVCL — еще один хороший выбор .

Создан 25 ноя. 11 2011-11-25 14:11:10 0xC0000022L

Да jvcl inc совершенен. Существует только каждая директива компилятора для кодирования некоторых разделов, относящихся к конкретным версиям. – az01 25 ноя. 11 2011-11-25 14:18:50

Директива компилятора Delphi для оценки аргументов в обратном порядке — delphi

Я был очень впечатлен этим delphi двумя лайнерами, используя функцию IFThen из Math.pas. Однако сначала он оценивает DB.ReturnFieldI, что является неудачным, потому что мне нужно вызвать DB.first, чтобы получить первую запись.

(как бессмысленное разъяснение, потому что у меня уже есть много хороших ответов. Я забыл упомянуть, что 0 — это код, который DB.First возвращает, если он что-то получил в нем, возможно, не имел смысла в противном случае)


Очевидно, это не такая уж большая проблема, как я мог бы заставить ее работать с пятью прочными лайнерами. Но все, что мне нужно для этого, — это использовать Delphi для оценки DB.first сначала и DB.ReturnFieldI. Я не хочу менять math.pas, и я не думаю, что это гарантирует мне перегрузку, потому что там, как 16 функций.

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

    6 4
  • 19 окт 2020 2020-10-19 15:25:35
  • Peter Turner

4 ответа

AFAIK нет директивы компилятора для управления этим. Если вы не используете соглашения stdcall/cdecl/safecall, параметры передаются слева направо в стеке, но поскольку соглашение по регистру по умолчанию может также передавать параметры в регистрах, может случиться так, что параметр будет вычисляться позже поместить в регистр перед вызовом. И поскольку только фиксированный порядок фиксирован (EAX, EDX, ECX) для параметров, которые соответствуют критериям, регистры могут быть загружены в любом порядке. Вы могли бы попытаться принудительно использовать соглашение о вызове «pascal» (в любом случае вам нужно будет переписать функцию), но IMHO всегда опасно полагаться на такой код, если компилятор не может явно гарантировать порядок оценки. И введение порядка оценки может значительно уменьшить количество доступных оптимизаций.

  • 19 окт 2020 2020-10-19 15:25:36
  • [email protected]

Не можете ли вы изменить свой запрос, чтобы иметь только один результат, чтобы избежать команды «Первый»? Также как:

  • 19 окт 2020 2020-10-19 15:25:36
  • philnext

соглашение о вызове влияет на способ их оценки.
Для этого не существует компилятора.

Pascal — это вызов, который вы должны использовать для получения этого поведения.

Хотя я лично никогда не буду зависеть от этого типа поведения.

В следующей примерной программе показано, как это работает.

Это потребует от вас написать свои собственные функции IfThen.

Если вы действительно хотите, чтобы это был один лайнер, вы действительно можете это сделать в Delphi. Я просто думаю, что это выглядит уродливо.

  • 19 окт 2020 2020-10-19 15:25:36
  • Robert Love

Обычно порядок оценки выражений undefined. (C и С++ аналогичны. Java всегда оценивает слева направо.) Компилятор не контролирует его. Если вам нужно два выражения для оценки в определенном порядке, напишите свой код по-разному. Я бы не стал беспокоиться о количестве строк кода. Линии дешевы; используйте столько, сколько вам нужно. Если вы часто используете этот шаблон, напишите функцию, которая завершает все:

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

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

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

Соглашение о вызове pascal передает аргументы слева направо в стеке. Это означает, что самый левый аргумент находится в нижней части стека, а самый правый аргумент находится вверху, чуть ниже адреса возврата. Если функция IfThen использовала этот вызов, существует несколько способов, которыми компилятор мог бы достичь этого макета стека:

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

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

Сначала выделите пространство стека и оцените в любом порядке:

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

Соглашение о вызове по умолчанию также передает аргументы слева направо, но первые три аргумента, которые соответствуют, передаются в регистры. Однако регистры, используемые для передачи аргументов, также являются реестрами, наиболее часто используемыми для оценки промежуточных выражений. Результат DB.First = 0 необходимо было передать в регистр EAX, но компилятор также нуждался в этом регистре для вызова ReturnFieldI и для вызова First . Вероятно, было бы гораздо удобнее сначала оценить вторую функцию, например:

Еще одно замечание: ваш первый аргумент является составным выражением. Там вызов функции и сравнение. Там нечего гарантировать, что эти две части выполняются последовательно. Компилятор может сначала вызвать вызовы функций, вызвав First и ReturnFieldI , а затем сравните возвращаемое значение First с нулем.

Директивы компилятора в Delphi

Есть ли в Delphi 7 директива компилятору по обработке исключений, регулируемых в процессе отладки галочкой Stop on Delphi Exception?

справку по директивам компилятора почитать не ?


> справку по директивам компилятора почитать не ?

зачем читать если можно спросить и заниматься своими делами. Но у меня, честно говоря, просто не было времени выяснять. А вообще я за RTFM


> зачем читать если можно спросить и заниматься своими делами

разумный подход, черт побери.


> зачем читать если можно спросить и заниматься своими делами.

Если эту логику чуть дальше развернуть, то получится, что зачем вообще работать? На этом форуме спрошу как делать это, на другом — как другое, на третьем — третье. А сам буду на диване лежать и фапать в потолок.

Что-то я не понял о чем речь?
Какая связь между директивами компилятора и поведением отладчика?

> Ega23 (15.04.2010 00:01:04) [4]

Остался один не достаток, спрашивать надо, бот бы еще без этого.

вот вы любители пофлеймить, дай только причину )))
ладно, шучу. Мануал так и не читал, потому что нет времени пока.

Проблема в том что мне надо в процессе отладки какого то алгоритма, видеть экцепшены, а некая логика завязана на них, то есть если я включу их индикацию то я буду ловить в отладчике все исключения, и зря останавливаться на тех, которые я ловлю в секциях try except. Вернее я их все ловлю но, определённого типа исключения я ловлю в циклах, а других типов только единожды. Вот если бы как то включить одни типы, а выключить другие — было бы круто!


> Константин (17.04.10 13:10) [7]


> было бы круто!

все и так круто.. заходим в опции дельфи и там находим что-то типа
Debugger Options -> Language Exception

> Константин (17.04.2010 13:10:07) [7]

Мануал все таки читай. Времени для этого более чем достаточно, программировать пока не надо.

Какие есть директивы компилятора?

Директивы условной компиляции
<$C+>и <$C->— директивы проверки утверждений
<$I+>и <$I->— директивы контроля ввода/вывода
<$M>и <$S>— директивы, определяющие размер стека

<$M+>и <$M->— директивы информации времени выполнения о типах
<$Q+>и <$Q->— директивы проверки переполнения целочисленных операций

<$R>— директива связывания ресурсов

<$R+>и <$R->— директивы проверки диапазона

<$APPTYPE CONSOLE>— директива создания консольного приложения

1) Директивы компилятора, разрешающие или запрещающие проверку утверждений.

По умолчанию <$C+>или

Область действия локальная

Директивы компилятора $C разрешают или запрещают проверку утверждений. Они влияют на работу процедуры Assert,используемой при отладке программ. По умолчанию действует
директива <$C+>и процедура Assert генерирует исключение EAssertionFailed, если проверяемое утверждение ложно.

Так как эти проверки используются только в процессе отладки программы, то перед ее окончательной компиляцией следует указать директиву <$C->. При этом работа процедур Assert будет блокировано и генерация исключений EassertionFailed производиться не будет.

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

2) Директивы компилятора, включающие и выключающие контроль файлового ввода-вывода.

По умолчанию <$I+>или

Область действия локальная

Директивы компилятора $I включают или выключают автоматический контроль результата вызова процедур ввода-вывода Object Pascal. Если действует директива <$I+>, то при возвращении процедурой ввода-вывода ненулевого значения генерируется
исключение EInOutError и в его свойство errorcode заносится код ошибки. Таким образом, при действующей директиве <$I+>операции ввода-вывода располагаются в блоке try. except, имеющем обработчик исключения EInOutError. Если такого блока нет, то обработка производится методом TApplication.HandleException.

Если действует директива <$I->, то исключение не генерируется. В этом случае проверить, была ли ошибка, или ее не было, можно, обратившись к функции IOResult. Эта функция очищает ошибку и возвращает ее код, который затем можно анализировать. Типичное применение директивы <$I->и функции IOResult демонстрирует следующий пример:

В этом примере на время открытия файла отключается проверка ошибок ввода вывода, затем она опять включается, переменной i присваивается значение, возвращаемое функцией IOResult и, если это значение не равно нулю (есть ошибка), то предпринимаются какие-то действия в зависимости от кода ошибки. Подобный стиль программирования был типичен до введения в Object Pascal механизма обработки исключений. Однако сейчас, по-видимому, подобный стиль устарел и применение директив $I потеряло былое значение.

3) Директивы компилятора, определяющие размер стека

Область действия глобальная

Локальные переменные в процедурах и функциях размещаются в стеке приложения. При каждом вызове процедуры или функции ее локальные переменные помещаются в стек. При выходе из процедуры или функции эти локальные процедуры удаляются из стека.
Директивы компилятора $M задают параметры стека приложения: его минимальный и максимальный размеры. Приложение всегда гарантированно имеет размер стека, равный его минимальной величине. Если при запуске приложения Windows обнаруживает, что не может
выделить этот минимальный объем памяти, то выдается сообщение об этой ошибке.

Если во время работы выясняется, что минимального размера стека не хватает, то размер увеличивается на 4 K, но не более, чем до установленного директивой максимального размера. Если увеличение размера стека невозможно из-за нехватки памяти или из-за достижения его максимальной величины, генерируется исключение EStackOverflow. Минимальный размер стека по умолчанию равен 16384 (16K). Этот размер может изменяться параметром minstacksize
директивы <$M>или параметром number директивы <$MINSTACKSIZE>.

Максимальный размер стека по умолчанию равен 1,048,576 (1M). Этот размер может изменяться параметром maxstacksize директивы <$M>или параметром number директивы <$MAXSTACKSIZE number>. Значение минимального размера стека может задаваться целым числом в диапазоне между1024 и 2147483647. Значение максимального размера стека должно быть не менее минимального размера и не более 2147483647. Директивы задания размера стека могут включаться только в программу и не должны использоваться в библиотеках и модулях.

В Delphi 1 имеется процедура компилятора <$S>, осуществляющая переключение контроля переполнения стека. Теперь этот процесс полностью автоматизирован и директива <$S>оставлена только для обратной совместимости.

4) Директивы компилятора, включающие и выключающие генерацию информации времени выполнения о типах (runtime type information — RTTI).

По умолчанию <$M->или

Область действия локальная

Директивы компилятора $I включают или выключают генерацию информации времени выполнения о типах (runtime type information — RTTI). Если класс объявляется в состоянии <$M+>или является производным от класса объявленного в этом состоянии, то компилятор генерирует RTTI о его полях, методах и свойствах, объявленных в разделе published. В противном
случае раздел published в классе не допускается. Класс TPersistent, являющийся предшественником большинства классов Delphi и все классов компонентов, объявлен в модуле Classes в состоянии <$M+>. Так что для всех классов, производных от него, заботиться о директиве <$M+>не приходится.

5) Директивы компилятора, включающие и выключающие проверку переполнения при целочисленных операциях

По умолчанию <$Q->или

Область действия локальная

Директивы компилятора $Q включают или выключают проверку переполнения при целочисленных операциях. Под переполнением понимается получение результата, который не может сохраняться в регистре компьютера. При включенной директиве <$Q+>проверяется переполнение при целочисленных операциях +, -, *, Abs, Sqr, Succ, Pred, Inc и Dec. После каждой из этих операций размещается код, осуществляющий соответствующую проверку. Если обнаружено переполнение,
то генерируется исключение EIntOverflow. Если это исключение не может быть обработано, выполнение программы завершается.

Директивы $Q проверяют только результат арифметических операций. Обычно они используются совместно с директивами <$R>, проверяющими диапазон значений при присваивании.
Директива <$Q+>замедляет выполнение программы и увеличивает ее размер. Поэтому обычно она используется только во время отладки программы. Однако, надо отдавать себе отчет, что отключение этой директивы приведет к появлению ошибочных результатов расчета в случаях, если переполнение действительно произойдет во время выполнении программы. Причем сообщений о подобных ошибках не будет.

6) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Директива компилятора <$R>указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows. По умолчанию расширение файлов ресурсов — .RES. В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах <$R>, копируются в
выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву <$R>, а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories/Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.

При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл .pas директиву <$R *.DFM>, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и сгенерируется исключение EResNotFound.

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

По умолчанию <$R->или

Область действия локальная

Директивы компилятора $R включают или выключают проверку диапазона целочисленных значений и индексов. Если включена директива <$R+>, то все индексы массивов и строк и все присваивания скалярным переменным и переменным с ограниченным диапазоном значений проверяются на соответствие значения допустимому диапазону. Если требования
диапазона нарушены или присваиваемое значение слишком велико, генерируется исключение ERangeError. Если оно не может быть перехвачено, выполнение программы завершается.

Проверка диапазона длинных строк типа Long strings не производится.
Директива <$R+>замедляет работу приложения и увеличивает его размер. Поэтому она обычно используется только во время отладки.

8) Директива компилятора, связывающая с выполняемым модулем файлы ресурсов

Область действия локальная

Директива компилятора <$R>указывает файлы ресурсов (.DFM, .RES), которые должны быть включены в выполняемый модуль или в библиотеку. Указанный файл должен быть файлом ресурсов Windows. По умолчанию расширение файлов ресурсов — .RES.
В процессе компоновки компилированной программы или библиотеки файлы, указанные в директивах <$R>, копируются в выполняемый модуль. Компоновщик Delphi ищет эти файлы сначала в том каталоге, в котором расположен модуль, содержащий директиву <$R>, а затем в каталогах, указанных при выполнении команды главного меню Project | Options на странице Directories/Conditionals диалогового окна в опции Search path или в опции /R командной строки DCC32.

При генерации кода модуля, содержащего форму, Delphi автоматически включает в файл .pas директиву <$R *.DFM>, обеспечивающую компоновку файлов ресурсов форм. Эту директиву нельзя удалять из текста модуля, так как в противном случае загрузочный модуль не будет создан и сгенерируется исключение EResNotFound.

Илон Маск рекомендует:  Основы языка PHP
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL