Б) Императорские заботы. После постройки империи (главы 57 и 58) бывшие независимые государства стали провинциями и породили новые проблемы. Для доставки туда правительственных бумаг император нанял гонцов. Чтобы доставка была по возможности скорой, гонцы следовали кратчайшими путями лишь в одном направлении – от центра к окраинам империи. Сколько гонцов для этого нужно? – вот первый вопрос. Сколько времени потребуется для достижения самых дальних окраин, если переход из провинции в провинцию отнимает сутки? – это второй вопрос. В конечных пунктах (на окраинах) перед возвращением гонцам нужен отдых, что это за окраины, где надо построить гостиницы? – это третий вопрос.
Подсказка: возьмите за основу программу «P_58_1» – обход графа в ширину – и внесите необходимые дополнения в процедуру Expand.
Глава 60
Мелкие хитрости
Нелегко совладать с крупным проектом, и тут не грех прибегнуть ко всяким уловкам и хитростям!
Рассмотрим ещё одно средство дробления программного проекта – включаемые файлы, которые называют ещё INCLUDE–файлами. В сравнении с библиотечными модулями возможности этих файлов скромны, но каждая вещь хороша на своем месте.
Механизм включаемых файлов до безобразия прост: содержимое такого файла как бы вставляется в другой. Место вставки определяется директивой $I, за которой следует имя вставляемого файла. Вы скажете, что вставку можно сделать иначе – редактором текста. Но ценность директивы $I в том, что вставки как таковой не происходит, – оба файла не изменяются. Но в момент компиляции проекта включаемый файл как бы составит часть того файла, в который он «вставлен».
Вот пример. Создадим и сохраним в рабочей папке два файла, первый из которых назовем «HELLO.INC», и в нём будет лишь одна строка.
Writeln(’Привет!’);
Второй файл – «HELLO.PAS» – будет таким.
begin {--- Главная программа HELLO.PAS ---}
{$I Hello}
end.
Компиляция файла «HELLO.PAS» породит приветливую программу. Здесь в директиве $I указано имя вставляемого файла без расширения, поскольку расширение INC берется по умолчанию. Разумеется, что INCLUDE–файл не вставишь куда попало, – его содержимое должно сочетаться с тем окружением, в которое его погружают.
Незамысловатый механизм включаемых файлов даёт ощутимую пользу, вот пример. Предположим, вы работаете над крупным проектом, состоящим из нескольких модулей. Время от времени вам надо компилировать эти модули вместе с первичным файлом так, чтобы опции компилятора для всех файлов совпадали. Такого совпадения можно добиться следующим образом:
Сначала настройте нужные опции компилятора через пункт меню Options –> Compiler…. Затем создайте новый файл и вставьте в него директивы компиляции нажатием комбинации Ctrl+O+O; в результате в файле могут оказаться такие, например, строки.
{$A+,B-,D+,E-,F-,G+,I-,L+,N+,O-,P-,Q-,R-,S-,T+,V-,X+,Y+}
{$M 16384,0,655360}
Сохраните этот файл, пусть он называется «Options.inc» (не забудьте указать расширение). Затем в первой строке каждого модуля, где вы намерены применить эти опции, вставьте директиву {$I Options}.
{$I Options}
...
Теперь компиляция всех файлов с одинаковыми настройками гарантирована, поскольку опции, заданные в директивах, преобладают над «менюшными». Потребовалось изменить настройки? – тогда исправьте только файл «Options.inc» и повторно откомпилируйте проект.
Моряка украшает загрубелое лицо, землекопа выдают мозолистые руки, а программиста – шишки, набитые при отладке программ. И это не шутка! Отладка – пожалуй, самая сложная часть работы, и здесь уместны разные хитрости.
Одно из таких ухищрений – печать промежуточных результатов или так называемая трассировка, – вы знакомы с этим приемом. По завершении отладки, расставленные там и сям, операторы трассировки только мешают, – их приходится удалять. Умные программисты не убирают их навсегда, а комментируют, то есть заключают в фигурные скобки, – а вдруг ещё пригодятся? А хитрые поступают иначе. «Зачем мне копаться в файлах проекта, выискивая лишние операторы? – рассуждают они, – пусть компилятор сделает это сам». Здесь они уповают на условную компиляцию.
Условная компиляция – это механизм, встроенный в компиляторы многих современных языков. Через него можно указать части программы, которые, в определенных случаях, компилировать не следует. Пропущенные таким образом куски программы равносильны комментариям. Условная компиляция организуется двумя директивами, с которыми мы сейчас ознакомимся.
Первая из них – $DEFINE – определяет некоторое имя. Это имя никак не связано с именами переменных, процедур и прочих объектов программы и может даже совпадать с ними – это не опасно. Определенное директивой имя используется лишь для условной компиляции так, как это будет показано далее. Вот парочка примеров определения таких имен.
{ $define Test }
{ $define Print }