Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Языки программирования. Практический сравнитель...doc
Скачиваний:
31
Добавлен:
09.09.2019
Размер:
2.68 Mб
Скачать

3.3. Библиотекарь

Можно хранить объектные модули либо в отдельных файлах, либо в одном файле, называемом библиотекой. Библиотеки могут поставляться с компи­лятором, либо приобретаться отдельно, либо составляться программис­том.

Многие конструкции языка программирования реализуются не с по­мощью откомпилированного кода, выполняемого внутри программы, а через обращения к процедурам, которые хранятся в библиотеке, предусмотренной поставщиком компилятора. Из-за увеличения объема языков программиро­вания наблюдается тенденция к размещению большего числа функциональ­ных возможностей в «стандартных» библиотеках, которые являются неотъем­лемой частью языка. Так как библиотека — это всего лишь структурированная совокупность типов и подпрограмм, не содержащая новых языковых конст­рукций, то она упрощает задачи как для студента, который должен изучить язык, так и для разработчика компилятора.

Основной набор процедур, необходимых для инициализации, управления памятью, вычисления выражений и т.п., называется системой времени исполнения (run-time system) или исполняющей системой. Важно, чтобы програм­мист был знаком с исполняющей системой используемого компилятора: не­винные на первый взгляд конструкции языка могут фактически приводить к вызовам времяемких процедур в исполняющей системе. Например, если высокоточная арифметика реализована библиотечными процедурами, то замена всех целых чисел на длинные (двойные) целые значительно увеличит время выполнения.

3.4. Компоновщик

Вполне возможно написать программу длиной в несколько тысяч строк в виде отдельного файла или модуля. Однако для больших программных сис­тем, особенно разрабатываемых группами программистов, требуется, чтобы программное обеспечение было разложено на модули (гл. 13). Если обраще­ние делается к процедуре, находящейся вне текущего модуля, компилятор никак не может узнать адрес этой процедуры. Вместо этого адреса в объек­тном модуле записывается внешняя ссылка. Если язык разрешает разным модулям обращаться к глобальным переменным, то внешние ссылки долж­ны быть созданы для каждого такого обращения. Когда все модули отком­пилированы, компоновщик разрешает эти ссылки, разыскивая описания процедур и переменных, которые экспортированы из модуля для нелокаль­ного использования.

В современной практике программирования модули активно используют­ся для декомпозиции программы. Дополнительный эффект такой практики — то, что компиляции бывают обычно короткими и быстрыми, зато компонов­щик должен связать сотни модулей с тысячами внешних ссылок. Эффектив­ность компоновщика может оказаться критичной для производительности группы разработчиков программного обеспечения на заключительных стади­ях разработки: даже незначительное изменение одного исходного модуля по­требует продолжительной компоновки.

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