Программирование на Lazarus

Консольные приложения и параметры программы

Показывать лекцию целиком

Цель лекции

Освоить работу с консольными приложениями и с параметрами программы.

Консольные приложения

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

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

Если вы пользуетесь операционной системой Windows, то нажмите на "Пуск" и выберите команду "Выполнить". В открывшемся окне наберите

cmd
    

и нажмите <Enter>. Откроется командная консоль, в которой команды нужно вводить в текстовом режиме:

(рис 21.1) Консоль cmd.exe

Собственно, вы видите окно предка Windows - операционной системы MS-DOS. Именно так выглядел экран с загруженной ОС MS-DOS, и управлять ею приходилось, вручную набивая всевозможные команды. Это уже позже корпорация Microsoft навесила на ядро MS-DOS всевозможные драйверы и утилиты, снабдила его графическим оконным интерфейсом, и появилась сначала полуграфическая ОС Windows 3.10 (русский вариант был 3.11 версии), а затем и целиком графическая Windows 95. Но к консольному ядру системы можно обращаться и в современных ОС, в Windows для этого используется программа cmd.exe, а в ОС Linux - терминал.

Все языки высокого уровня позволяют делать и консольные приложения, другое дело - зачем? Подавляющее большинство современных программ имеет графический интерфейс, который мы с вами создавали с самой первой лекции. А консольные приложения делаются в основном, системными программистами. Несмотря на то, что Object Pascal обладает для этого всеми необходимыми инструментами, системщики обычно пользуются такими языками, как Ассемблер, C, реже - C++. Но все же знать, как создаются консольные приложения нужно, поэтому данную лекцию мы посвящаем им.

Создание консольного приложения

Создать консольное приложение можно разными способами, но проще всего так. Откройте Lazarus. Командой "Проект -> Закрыть проект" закройте текущий проект, автоматически появится окно Мастера создания проекта. В нем нажмем кнопку "Новый проект". Появится окно создания проекта, в котором можно выбрать "Программа" или "Консольное приложение". Если мы выберем "Программа", то будет создан модуль с минимальным кодом. Если же мы выберем "Консольное приложение", то кода будет больше, так как при этом создается программа с новым классом, производным от TCustomApplication. TCustomApplication обеспечивает хорошую основу и делает программирование утилит командной строки довольно простым. Например, проверку опций командной строки, написание справки, проверку переменных окружения и обработку исключений. Все программы LCL автоматически это используют.

Но нам не нужно использовать возможности класса TCustomApplication, мы делаем простую консольную программу, поэтому в окне создания проекта мы выбираем "Программа". Сформируется проект, а в Редакторе исходного кода будет минимум текста:

program Project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };

begin
end.
    

Обратите внимание, если нам нужно подключить к программе какие то модули, то делать это нужно до комментария

  { you can add units after this };
    

В этом случае мы ставим запятую после указанного модуля Classes и добавляем свои модули. Завершающая точка с запятой стоит после комментария, нам её ставить не нужно.

Свой код мы будем писать между скобками

begin
end.
    

А если нам потребуется указать глобальные константы, переменные или сделать объявления процедур и функций, то все это делается до begin.

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

WRITE и WRITELN

Процедура Write предназначена для вывода информации на экран. Она имеет следующий синтаксис:

procedure Write(var F:Text; Args:Arguments);
    

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

  write('Всем привет!!!');
  write('Переменная a = ', a, '; переменная b = ', b);
    

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

Процедура Writeln действует точно также, но после вывода последнего символа курсор переходит на начало следующей строки.

Для ознакомления с процедурами создайте новый проект "Программа". Модуль можно не переименовывать, просто сохраните его в папку 21-01. Полный текст модуля следующий:

program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };

var a, b: Integer;
begin
  a:= 5;
  b:= 10;
  writeln('Всем привет!!!');
  writeln('Переменная a = ', a, '; переменная b = ', b);
  readln();
end.
    

Обратите внимание: раздел переменных var мы указали до служебного слова begin, то есть, переменные a и b в пределах модуля являются глобальными. Далее мы присвоили переменным значения, затем вывели на экран приветствие, а потом содержимое переменных. На процедуру readln() пока не обращайте внимания, она нужна только, чтобы программа не закрылась сразу же после вывода текста, а была на экране, пока мы не нажмем <Enter>. Сохраните проект и запустите его на выполнение. И сразу же мы видим недостаток: вместо русских букв выходит нечто, что в Интернете называют "кракозябры":

(рис 21.2) Неправильный вывод кириллицы в консольной программе

В лекции №5 мы упоминали, что в консольных приложениях Windows принято использовать кодировку CP866, тогда как в графических приложениях используется CP1251 и Юникод. Отсюда и "кракозябры". В Linux и Unix таких проблем нет. Однако решить эту проблему совсем несложно. Нажмите <Enter>, чтобы закрыть консоль, и вернитесь в Редактор кода. Щелкните по окну с кодом правой кнопкой мыши, и в открывшемся контекстном меню выберите команду "Параметры файла -> Кодировка -> CP866". Откроется окно смены кодировки, нам надо нажать кнопку "Изменить файл". Снова запустите программу на выполнение - теперь с кодировкой полный порядок:

(рис 21.3) Правильный вывод кириллицы в консольной программе

READ и READLN

Процедура Read предназначена для ввода информации в программу, точнее, в переменные. Процедура работает следующим образом:

read(Переменная1, Переменная2, …, ПеременнаяN);
    

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

read(i, r);
    

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

12 3.45
    

Как только он нажмет <Enter>, в переменную i попадет число 12, а в r - число 3,45. Если пользователь введет некорректные данные, не соответствующие типу переменной, то возникает ошибка и программа аварийно завершает работу.

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

1 23 456
    

и нажал <Enter>. Эти данные могут быть обработаны следующими инструкциями:

read(a, b);
read(c);
    

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

readln(a, b);
read(c);
    

то в a и b попадут числа 1 и 23, после чего программа будет ожидать следующих данных, а число 456 потеряется.

Если указать read или readln без параметров, например, так:

readln();
    

то программа просто перейдет в режим ожидания, пока пользователь не введет <Enter>. В конце консольных приложений всегда желательно указывать такую пустую readln, иначе программа просто мигнет и выключится, не дав пользователю увидеть результаты работы. Или можно как-то иначе обеспечить работу программы до тех пор, пока пользователь сам не захочет ее закрыть. Например, иногда программисты выводят сообщение типа "Продолжить работу программы? 0-нет, 1-да". Если пользователь введет 0, то программа завершится, а если 1, то продолжит работу. Какой способ использовать - дело ваше.

Чтобы пользователь понимал, чего от него хочет программа, перед каждой инструкцией read или readln следует с помощью write или writeln выводить поясняющий текст.

Вернемся к нашей программе, и немного изменим код (между begin и end.):

begin
  write('Введите первое целое число: ');
  readln(a);
  write('Введите второе целое число: ');
  readln(b);
  writeln('Результат:');
  writeln('Переменная a = ', a, '; переменная b = ', b);
  readln();
end.
    

Теперь программа выводит запрос "Введите первое число:", и замирает, ожидая от пользователя ввода данных. После того, как он введет число и нажмет <Enter>, программа таким же образом запросит второе число. Затем она выведет результат, и будет ожидать, пока пользователь не нажмет <Enter>:

(рис 21.4) Результат работы программы

Параметры консольного приложения

Нередко системные консольные программы вызываются с какими-то параметрами. Например, в Windows можно нажать "Пуск -> Выполнить" и указать следующую команду:

ping 127.0.0.1 -t
    

В результате будет запущена консольная утилита ping.exe, которая делает трассировку (обмен данными) с указанным IP-адресом. Таким образом, проверяют, есть ли связь с данным адресом. В примере программа запускается с двумя параметрами. Первым параметром является IP-адрес 127.0.0.1 - это адрес локальной машины, обращаясь к 127.0.0.1, вы обращаетесь к своему же компьютеру. Вторым параметром является

-t
    

Этот параметр указывает утилите, что не следует завершать обмен данными, пока пользователь сам не прервет работу программы. Если не указать -t, программа сделает 4 попытки отправить данные, после чего завершит свою работу. С параметром -t программа будет работать, пока пользователь не нажмет <Ctrl+C>.

Возможно, когда-нибудь и нам потребуется создать программу (не обязательно консольную), умеющую принимать и обрабатывать параметры. Для обработки параметров используются две функции: ParamCount и ParamStr.

ParamCount возвращает количество параметров, переданных в программу.

ParamStr(i) возвращает параметр под индексом i - индексация начинается с 1. Например, вывести на экран первый и последний параметры можно так:

ShowMessage('Первый параметр: ' + ParamStr(1);
ShowMessage(Последний параметр: ' + ParamStr(ParamCount);
    

Однако имейте в виду, что в любой программе, консольной или обычной, даже запущенной совсем без всяких параметров, доступен и "нулевой" параметр ParamStr(0) - в нем всегда находятся адрес и имя файла программы.

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

Имейте в виду, что все параметры, даже числа, вводятся в виде текста, так что для работы с целыми числами нам придется использовать функции IntToStr и StrToInt. А обе эти функции описаны в модуле SYSUTILS, который нам придется подключить в разделе uses. Вот полный листинг программы:

program project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils
  { you can add units after this };

var a, b: integer;
begin
  //если параметров вообще нет:
  if ParamCount = 0 then begin
    write('Введите первое целое число: ');
    readln(a);
    write('Введите второе целое число: ');
    readln(b);
  end
  //если только один параметр:
  else if ParamCount = 1 then begin
    a:= StrToInt(ParamStr(1));
    write('Введите целое число: ');
    readln(b);
  end
  //если параметров больше одного:
  else begin
    a:= StrToInt(ParamStr(1));
    b:= StrToInt(ParamStr(2));
  end;
  //теперь вывод результатов:
  writeln('Всего параметров: ' + IntToStr(ParamCount));
  writeln('Запущена программа: ' + ParamStr(0));
  writeln('Переменная a = ', a, '; переменная b = ', b);
  readln();
end.
    

Обратите внимание, после модуля Classes мы указали модуль SysUtils. Далее, мы обеспечили ввод данных в a и b в случаях, если параметров вообще нет, если есть только один параметр, и если параметров больше, чем один. В конце мы выводим общее количество указанных параметров, нулевой параметр с указанием адреса и файла программы, и затем указываем значения переменных. В заключение указываем пустой readln, чтобы программа не закрылась, пока не захочет пользователь.

Сохраните проект и запустите его. Он загрузится без параметров, вам придется ввести оба числа вручную. Введите числа, полюбуйтесь на результат и закройте программу. Теперь загрузим ее с параметрами. Для этого нажмите "Пуск -> Выполнить", нажмите кнопку "Обзор", найдите и откройте наш проект, допишите после его имени один или два параметра, например, так:

(рис 21.5) Указание параметров программы

Как видите, в качестве параметров я указал два числа: 12 и 24. Программа не станет запрашивать у меня данные, а сразу выведет результат:

(рис 21.6) Результат работы программы

Поэкспериментируйте с программой, вызывая с различным количеством параметров.

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

Вернуться к учебному плану