Подтвердить что ты не робот

Как работает WriteLn()?

С возрастом динозавров, Turbo Pascal и в наши дни Delphi имеют процедуру Write() и WriteLn(), которая спокойно делает некоторые аккуратные вещи.

  • Число параметров является переменной;

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

  • Вы можете предоставить дополнительные параметры для каждого аргумента:

Write ( 'Hello': 10, 'World!': 7);//параметры выравнивания

  • Он даже проявляется особым образом в drowdown завершения кода:
    • Write ([var F: File]; P1; [..., PN])
    • WriteLn ([var F: File]; [P1; [..., PN]])

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

Во всяком случае, могу ли я написать такие процедуры, как это, или все это из-за какого-то волшебного жестко закодированного трюка компилятора?

4b9b3361

Ответ 1

Writeln - это то, что мы называем "магической" функцией компилятора. Если вы посмотрите в System.pas, вы не найдете Writeln, который будет объявлен как то, что вы ожидаете. Компилятор буквально разбивает все на отдельные вызовы на различные специальные функции библиотеки времени выполнения.

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

Ответ 2

Как сказал Аллен, вы не можете написать свою собственную функцию, которая делает все то же самое.

Однако вы можете написать драйвер текстового файла, который выполняет что-то обычное, и когда вы используете стандартный Write (ln) для записи в ваш драйвер текстового файла. Мы сделали это в старые дни DOS:)

( "Драйвер" в контексте предыдущего оператора - это всего лишь фрагмент кода Pascal, который подключен к системе путем переключения указателя в системном модуле IIRC. Прошло много времени с тех пор, как я в последний раз использовал этот трюк.)

Ответ 3

Насколько я знаю, стандарты pascal не включают переменные аргументы.

Сказав это, IIRC, GNU Pascal, вы можете сказать что-то вроде: Procecdure Foo (a: Integer; b: Integer;...);

Попробуйте выполнить поиск в своих документах на языке компилятора для "Переменные списки аргументов" или "Соответствующие массивы". Вот пример более позднего: http://www.gnu-pascal.de/demos/conformantdemo.pas.

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

Однако, если вы не пишете функцию "writeln" (которая уже написана), вам, вероятно, не нужно будет выполнять процедуру с переменными аргументами. Попробуйте выполнить итерацию или рекурсию:)

Ответ 4

Это поведение магического компилятора, а не регулярная процедура. И нет, нет способа написать такие подпрограммы (к сожалению!). Генерация кода разрешает подсчет фактических параметров и их типов и переводит на соответствующие RTL-вызовы (например, Str()) во время компиляции. Это противоречит часто предлагаемому массиву const (формальный параметр одиночного варианта массива, фактически), что приводит к тому, что он выполняется во время выполнения. Я нахожу, что позже подход неуклюжий, он несколько ухудшает читаемость кода, и Bugland (Borland/Inprise/Codegear/Embarcadero/name it) нарушил Code Insight для вариантов открытых конструкторов массива (да, я забочусь, я использую OutputDebugString (PChar (Format ( "...", [...])))) и завершение кода не работает должным образом (или вообще). Таким образом, максимально возможный способ моделирования магического поведения состоит в том, чтобы объявить множество перегруженных подпрограмм (на самом деле их много, по одному на определенный формальный тип параметра в конкретной позиции). Можно также назвать это kludge, но это единственный способ получить гибкость списка переменных параметров и может быть скрыт в отдельном модуле.

PS: я умышленно забыл спецификаторы формата, потому что синтаксис не позволяет использовать точки с запятой, где Str(), Write() и Writeln ( ) принимают их.

Ответ 5

Да, вы можете сделать это в Delphi и друзьях (например, бесплатный паскаль, Kylix и т.д.), но не в более "стандартных" паскалях. Посмотрите варианты открытого массива, которые используются с синтаксисом примерно так:

procedure MyProc(args : array of const);

(прошло несколько лет, и у меня нет ручных ручек, поэтому проверьте подробности перед продолжением). Это дает вам открытый массив TVarData (или что-то в этом роде), из которого вы можете извлечь RTTI.

Но одно примечание: я не думаю, что вы сможете сопоставить синтаксис форматирования x: y (это специальный) и, вероятно, придется использовать несколько более подробный обертку.

Ответ 6

Большинство уже сказано, но мне нравится добавлять несколько вещей.

Сначала вы можете использовать функцию Format. Целесообразно преобразовать практически любую переменную в строку и контролировать ее размер. Хотя у него есть свои недостатки:

myvar := 1;
while myvar<10000 do begin
  Memo.Lines.Add(Format('(%3d)', [myVar]));
  myvar := myvar * 10;
end;

Выдает:

(  1)
( 10)
(100)
(1000)

Таким образом, размер минимального размера (как и конструкция: x: y).

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

procedure WriteSome(const A1: string; const A2: string = ''; const A3: string = '');

или

procedure WriteSome(const A1: string); overload;
procedure WriteSome(const A1: Integer); overload;

Ответ 7

Вы не можете написать свою собственную запись /writeln в старом Pascal. Они генерируются компилятором, форматированием, обоснованием и т.д. Поэтому некоторые программисты, такие как язык C, даже гибкие стандартные функции, например. printf, scanf, могут быть реализованы любыми компетентными программистами.

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

P.S.

Но, как отметил MarkusQ, некоторые варианты Pascal (Free Pascal, Kylix и т.д.) могут облегчить переменные аргументы. Я последний раз возился с Паскалем, так как дни DOS, Turbo Pascal 7.

Ответ 8

Writeln не является "массивом const", а разложен компилятором на различные вызовы, которые преобразуют аргументы в строку, а затем вызывают примитивный сценарий. "LN" - это просто функция, которая записывает листинг как строку. (Зависит от ОС). Переменные процедуры (указатели функций) для примитивов являются частью типа файла (Textrec/filerec), поэтому их можно настроить. (например, AssignCrt в TP)

Если включен режим {$ я +}, после каждого элемента выполняется вызов функции iocheck.

Конструкция GPC, сделанная выше, является afaik безграничным C открытым массивом. FPC (и afaik Delphi тоже) тоже поддерживают это, но с другим синтаксисом.

процедура somehting (a: массив const); cdecl;

будет преобразован в ABI, совместимый с стилем C, printf. Это означает, что соответствующая функция (в этом случае не может быть использована) не может получить количество аргументов, но должна полагаться на синтаксический разбор форматирования. Так что это нечто отличное от массива const, который безопасен.

Ответ 9

Если вы не ответили на свой вопрос, я хотел бы добавить следующий комментарий: Недавно я переписал некоторый код, используя синтаксис Writeln (...), используя StringList, заполнив "строки" с помощью Format (...) и просто встроенные функции IntToStr (...), FloatToStr (...) и как.

Основной причиной этого изменения было улучшение скорости. Использование StringList и SaveFileTo выполняется намного быстрее, чем комбинация WriteLn, Write.

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