Р.У. Себеста - Основные копцепции языков программирования (2001) (1160794), страница 49
Текст из файла (страница 49)
Вместо этого переменная связывается с типом при присвоении ей значения оператором присваивания. При выполнении оператора присваивания переменная, которой присваивается значение, связывается с типом переменной, выражения или значения, находящегося в правой части оператора присваивания.
4А. Концепция связывания Языки, в которых типы связываются динамически, значительно отличаются от языков со статическим связыванием типов. Основным преимушеством динамического связывания переменных с типом является то, что оно обеспечивает значительную гибкость программирования. Например, программу обработки таблицы данных в языке, использующем динамическое связывание типов, можно написать в виде настраиваемой программы. Это означает, что программа сможет работать с данными любого типа. Любой тип входных данных будет приемлемым, поскольку переменные, предназначенные для их хранения, после ввода этих данных будут связываться с соответствующим типом во время присваивания. В отличие от динамического статическое связывание типов не позволяет написать на языках С нли Разов! программу обработки таблицы данных без уточнения типа данных.
В языках АРЬ и ЯЧОВОЬ4 связывание переменных с типом происходит динамически. Например, в программе на языке АРЬ может содержаться следующий оператор: ЫВТ <- 10. 2 5. 1 О. 0 Независимо от предыдущего типа переменной Ы ЯТ в результате этого присваивания она станет обозначать одномерный массив длины 3, содержащий числа с плавающей точкой. Если оператор ЫЯТ ь- 47 будет выполнен после написанною выше присваивания, то переменная ЫЯТ станет целочисленной скалярной переменной. У линамического связывания типов есть два недостатка.
Во-первых, поскольку по обе стороны оператора присваивания могут находиться величины двух любых типов, то возможность обнаружения компилятором ошибок снижается по сравнению с языками со статическим связыванием типов. Неверные типы в правой стороне оператора присваивания не будут расценены как ошибки; вместо этого просто произойдет изменение типа левой стороны оператора присваивания на этот неверный тип. Предположим, что в конкретной программе 1 и х — целочисленные переменные, а у — массив, содержащий числа с плавающей точкой.
Предположим также, что в программе необходим оператор присваивания х Однако при наборе оператор был записан в виде В языке с динамическим связыванием типов ни система компиляции, ни система поддержки выполнения программ не обнаружат ошибку. Тип переменной 1 просто будет изменен на тип массива, содержащего числа с плавающей точкой. Поскольку вместо правильной перемененной х была использована переменная у, результаты программы будут ошибочными.
В языке со статическим связыванием типов компилятор обнаружит ошибку, и программа не будет выполнена. Отметим, что этот недостаток до некоторой степени присутствует и в таких языках, использующих статическое связывание типов, как гОКТВАН, С и С++, которые во многих случаях автоматически преобразовывают тип правой части оператора присваивания в тип его левой части. 162 Елово 4. Имена, связывание, проверка типов и области видимости Другим недостатком динамического связывания типов является его цена, которая весьма значительна, особенно во крался выполнения.
Именно в это время должна производиться проверка типов. Более того, каждая переьсенная должна содержать дескриптор. связанный с нею, для запоминания текушего типа. Память. используемая лля хранения переменной. должна быть переменного размера, поскольку значения различных типов требуют различных объемов памяти. Языки, имеюшие динамическое связывание типов переменных. часто реализовываются с помощью интерпретаторов. а не компиляторов.
Это происходит отчасти из-за сложности динамического изменения типов переменных в машинных колах. Более того, время, необходимое для динамического связывания типов, перекрывается обшим временем интерпретации, так что в этой среде динамическое связывание кажется более дешевым. С другой стороны, языки со статическим связыванием типов резко реализуются с помошью интерпретаторов, поскольку программы, написанные на этих языках.
легко могут транслироваться в эффективные версии в машинных кодах. Я.4.2.3. Логзтчвскмй вывод типа Относительно недавно был разработан язык М1., поддерживающий как функциональное, так и императивное программирование (МПег ес а1., 1990). Этот язык использует интересный механизм логического вывода типа, в котором типы большинства выражений могут определяться без участия програлсмиста. Например, объявление функции гип сйгсилзй(г) 3.14159 * г * гг определяет функцию, аргумент и результат которой имеют действительный тип. Их тип логически выводится из типа константы, входяшей в выражение.
Подобным образом в функции гип Гзжез10(х) 10 * х; логически выводится целый тип аргумента и значения функции. Система языка М). отвергнет функцию гиц зс(иаге(х) х * х; Это происходит потому, что тип оператора * определить невозможно. В полобных случаях программист может дать системе подсказку, подобную указанной ниже. в которой функция устанавливается как имеюшая тип 1пг. йип зс(илге(х): 1пг х * х; Факта, что значение функции указано целочисленным, достаточно для логического вывода, что аргумент также является целым. Вполне дозволены также следуюшие определения: Йип зйиаге(х с 1пг) = х * х; г'изз зс)саге(х) = (х: 1пг) * х; Еип зсрзаге(х) = х * (х: 1пг); Логический вывод типа также используется в чисто функциональных языках программирования М)галс)а и Наз)сеП.
4.4. Концепция связывания 4.4.3. Связывание переменных с ячейками памяти и время их жизни Основные свойства языка программирования в значительной степени опрелеляются разработкой способов связывания ячеек памяти с переменными. которые в них хранятся П з этого следует важность четкого понимания этих связей. Ячейки памяти, с которыми связываются переменные, каким-то образом должны изв.юкаться из пула доступной памяти. Этот процесс называется размещением в памяти (айосайоп).
Удаление из памяти (деайосайоп) — это процесс помещения ячейки памяти. открепленной от переменной, обратно в пул доступной памяти. (Следует обратить внимание на то. что с ячейкой и переменной, хранящейся в этой ячейке, производятся прямо противоположные действия.
Для связывания с некоей переменной свободная ячейка извлекается из пула свободной памяти, а переменная помещается в эту ячейку, з е. размещается в памяти. При разрыве связи между переменной и ячейкой переменная удаляется из памяти, а ячейка возвращается обратно в пул свободной памяти. По этой причине обычно термины рааиешение и удцзение относятся к переменной, а не к ячейке. — Прин. ред.) Время жизни переменной — это время. в течение которого переменная связана с определенной ячейкой памяти. Таким образом, время жизни переменной начинается при ее связывании с определенной ячейкой памяти и заканчивается при ее откреплении от этой ячейки. Для изучения связывания памяти с переменными удобно разделить скалярные (неструктурированные) переменные на четыре категории согласно их временам жизни.
Мы назовем этн категории статическими (ьтаггс), автоматическими (агаси-дупапбс). явными динамическими (ехрйси Ьеар-дупака) и неявными динамическими перелзенными (нпрйсй Ьеар-дупапйс). В следующих разделах рассматриваются эти четыре категории, в том числе их цели, лостоинства и недостатки. 4.4.3. 1. Статические переменные Статическими называются переменные. которые связываются с ячейкой памяти до начала выполнения программы и остаются связаннымн с той же самой ячейкой памяти шглоть до прекращения выполнения программы. Переменные, которые статически связываются с памятью, имеют несколько полезных применений в программировании. Очевидно.
что глобачьные переменные часто используются на всем протяжении программы, что делает необходимым их привязку к одному месту памяти в течение всего времени выполнения программы. Иногда бывает удобно. чтобы переменные, объявляемые в подпрограммах, зависели от прелыстории (п1згогу зепяйче).
т.е. сохраняли свое значение между отдельными выполнениями подпрограммы. Это как раз и является характеристикой переменной, статически связанной с памятью. Другим плюсом статических переменных является их эффективность. Вся адресация сзатических переменных может быть прямой, тогда как другие типы переменных часто требуют более медленной косвенной алресацни. Более того. на размещение статических переменных в памяти и улаление их из памяти в процессе выполнения программы не затрачивается дополнительное время. Одним из недостатков статического связывания с памятью является уменьшение гибкости; в частности, в языках, имеющих только статические переменные, не поддерживаются рекурсивные подпрограммы. Еше одним недостатком является невозможность совместного использования памяти несколькими переменными.
Предположим, что в про- 'з 84 Глава 4. Имена, связывание, проварко типов и области видимости грамме есть две подпрограммы. причем обеим нужны ботьшие. не связанные между собой массивы. Если они являются статическими, то память. в которой они хранятся. нельзя использовать совместно. В языках ГОКТКАН !. П и!Ч все переменные были статическими. Языки С. С-+ и )ата позволяют программисту включать в определение локальных переменных спецификатор вкасзо, делая их статическими. В языке Рааса! статические переменные не предусмотрены.
4.4.3.2. Автоматические неременные Автоматическими называются переменные, связывание памяти с которыми выполняется при обработке их операторов объявления. но типы которых связываются статически. Обработка (е!аЬогаг!оп) такого объявления означает распределение памяти и выполнение процессов связывания. укаэанных в объявлении. Эти действия происходят при достижении фрагмента кола. с которым связано объявление, в процессе выполнения программы. Следовательно, обработка происхолит во время выполнения программы.
Например. процедура языка Рааса! состоит из раздела объявлений и раздела операторов. Раздел объявлениИ обрабатывается непосредственно перед началом выполнения раздела операторов. происходяшего при вызове процедуры. Память для переменных. нахоляшихся в разделе объявления, выделяется во время обработки объявлений и освобождается после возврата процедурой управления вызывающему оператору. Как показывает их название, память автоматическим переменным выделяется из стека выполняемой программы (гцпч)ше эгас!с). Структура языка АЕООЕ 60 и последуюших языков позволяет использовать рекурсивные подпрограммы.
Для того чтобы быть полезными, по крайней мере в большинстве случаев, рекурсивным подпрограммам требуется некоторая динамическая локальная память для того, чтобы каждая активная копия рекурсивной подпрограммы имела свою собственную версию локальных переменных. Для удовлетворения этих требований используются автоматические переменные.