- •Понятие программы и языка программирования
- •Функция как компонент структуры программы
- •Примеры простых программ
- •Вычисление значения функции в заданной точке
- •Вычисление суммы и количества целых чисел, введенных пользователем с клавиатуры
- •Демонстрация работы со строками на основе использования класса string
- •Представление программы и данных
- •Процесс компиляции программы
- •Классическая схема подготовки исполняемой программы
- •Технологический цикл обработки программы
- •Особенности внутреннего представления программы и ее исполнения
- •Организация памяти компьютера
- •Сегментация программы
- •Процесс исполнения программного кода
- •Структура текстового файла программы
- •Структура программы из двух текстовых файлов
(4)– программа-ассемблер переводит ассемблерный код на машинный язык, создает
объект ный модуль программы с расширением .obj и сохраняет его на диске. Файл, содержащий скомпилированную программу, – это объектный модуль программы.
(5) – программа-компоновщик (редактор связей, Linker) объединяет объектный код программы (совместно компилируемые модули) с объектными кодами используемых ею библиотечных
функций (библиотечные файлы имеют расширение .lib) и стандартным кодом начальной загрузки, в результате чего создается исполняемый загрузочный модуль программы – файл с расширением
.exe, сохраняемый на диске. Обычно программы содержат ссылки на функции, определенные вне самой программы: в стандартных или личных библиотеках, а объектный код содержит «дыры» изза этих отсутствующих частей; компоновщик заполняет эти «дыры».
(6) – программа-загрузчик размещает скомпонованную программу в памяти (забирает исполняемый код с диска и размещает его в памяти).
Язык Си++ имеет прямой выход на компьютерную архитектуру, многие его компоненты напрямую на нее отображаются. Базовые типы данных совпадают с основными формами представления данных в процессоре, имеется прямое соответствие между переменными и машинными словами, набор операций соответствует общепринятому минимуму для системы команд, указатели интерпретируются как адреса, имеется возможность работы с памятью на низком (архитектурном) уровне. Поэтому Си++ можно назвать машинно-независимым Ассемблером. Особенности выполнения указанных действий зависят от конкретного компилятора языка С++ и операционной системы, в которой он работает. Технические подробности следует изучить по документации конкретного программного продукта.
Технологический цикл обработки программы
Технологический цикл обработки программы выглядит следующим образом:
перевод с языка высокого уровня на машинный язык
создание исполняемого Создание (загрузочного) модуля
исходного
текста
Компи- Компоновка ляция
|
|
|
|
|
|
|
|
|
|
Отладка, |
|
|
|
|
|
|
|
|
|
|
тестиро- |
|
Исправление |
|
|
|
|
|
|
|
вание, |
|
|
|
|
|
|
|
|
|
|||
|
синтаксических |
|
|
|
|
|
|
|
выпол- |
|
|
ошибок |
Исправление |
|
|
нение |
|||||
|
|
|
||||||||
|
|
|
семантических |
|
|
|
||||
|
|
|
|
|
ошибок |
|
|
|
||
|
|
|
|
|
|
Синт аксис языка программирования описывает сист ему правил написания различных языковых конст рукций; нарушение этих правил приводит к синт аксическим ошибкам,
выявляемым на этапе компиляции программы в процессе синт аксического анализа;
Семант ика языка программирования – правила инт ерпрет ации операт оров – определяет
смысл языковых конст рукций, последовательность действий, которые выполнит компьютер при реализации написанного; нарушение этих правил приводит к семант ическим ошибкам, выявляемым в процессе семант ического анализа (трудно, а практически вообще не выявляемым на этапе компиляции и трудно выявляемым на этапе отладки и даже эксплуатации программы).
Особенности внутреннего представления программы и ее исполнения
Для понимания и осознанного использования многих особенностей языка программирования полезны знания о внутреннем представлении программы и принципах ее исполнения, а также о
Программирование – лекция 1 (лекции Стрикелевой Л.В.) |
12 |
|
компьютерной архитектуре. Попробуем представить все это на самой примитивной модели.
Организация памяти компьютера
Все данные, хранящиеся в памяти компьютера, представляются в двоичной системе счисления в виде машинных слов – наборов двоичных разрядов (совокупность битов – нулей и единиц). Биты объединяются в последовательности: байты, слова и т.д. Минимальный размер машинного слова для хранения, обработки и передачи данных – 8 битов (1 байт). Все остальные слова кратны ему. Ст андарт ное машинное слово имеет разрядность, соответствующую разрядности процессора (32 разряда или 4 байта).
Какой смысл заключен в данных, какими символами они выражены – буквенными или цифровыми, что означает то или иное число – все это определяется программой обработки. Все данные, необходимые для решения практических задач, подразделяются на несколько типов, причем понятие тип связывается не только с представлением данных в адресном пространстве, но и со способом их обработки. Данные могут быть отнесены к одному из двух типов: основному (простому), форма представления которого определяется архитектурой компьютера, или сложному, конструируемому пользователем для решения конкретных задач. Данные простого типа это – символы, числа и т.п. элементы, дальнейшее дробление которых не имеет смысла. Из элементарных данных формируются структуры (сложные типы) данных.
Основу компьютерной архитектуры составляет прямо адресуемая памят ь: массив элементарных ячеек памяти, номера кот орых называют ся адресами. Каждому участку оперативной памяти, который может вместить один байт или слово, присваивается адрес (порядковый номер). Как адрес памяти, так и ее содержимое представляют собой машинные слова.
Для представления содержимого машинных слов используется шестнадцатеричная система счисления. В дальнейшем описании мы будем применять более привычные десятичные значения, не забывая, что в реальности имеем дело с двоичными (шестнадцатеричными) эквивалентами.
Поэтому на самом низком уровне адрес можно рассматривать как целое число. Все формы представления данных (целые со знаком и без него, вещественные, символы) проецируются в двоичное представление и в машинные слова. Но!!!: хранятся числовые значения в памяти, начиная с младшего байта, в порядке, обратном привычному нам при записи чисел (Рис.1.4).
Процессор имеет в своем составе набор машинных слов – регист ров. В зависимости от назначения они могут хранить как данные, так и адреса памяти.
Рис. 1.4. Организация памяти компьютера
Программирование – лекция 1 (лекции Стрикелевой Л.В.) |
13 |
|
Сегментация программы
Следующий важный принцип организации памяти – сегментация. Сегмент ом называется непрерывная область памяти, хранящая данные одного вида (назначения) и имеющая собственную систему относительной адресации и ограничения доступа. К программированию это имеет отношение потому, что при трансляции разные компоненты программы попадают в различные сегменты программного кода.
Одновременное нахождение в памяти «алгоритма» и данных соответствует принципу хранимой программы, который заключается в том, что программный код хранится в той же самой памяти, что и обрабатываемые данные, и в свою очередь сам представляет собой специфические данные, с которыми работает процессор во время выполнения программы. В настоящее время применяется немодифицируемый программный код. Это, в свою очередь, означает, что несколько программ могут его читать и исполнять, не мешая друг другу, в то м числе и на физически параллельных процессорах.
Компоненты программы находятся в памят и, которая, в принципе, является общей для них, но логически разделяется на области, именуемые сегмент ами: прежде всего, это сегмент данных, содержащий данные программы, и сегмент кода, в котором находится алгоритмическая компонента (выражения, операторы).
Сегментация поддерживается в процессоре при помощи регистров двух видов. Базовый регист р сегмент а содержит его начальный адрес. Регистры, работающие с данными сегмента, содержат относительный адрес данных от начала сегмента, или смещение. Результирующий адрес получается путем сложения содержимого этих регистров. Таким образом, каждый сегмент имеет собственную «систему координат», связанную с его началом (Рис.1.5). Если программа использует только сегментную адресацию, то сегменты можно перемещать по памяти при сохранении работоспособности программы: достаточно перенастроить соответствующие им базовые регистры.
Выполняемая программа состоит из нескольких сегментов. Некоторые из них создаются при трансляции, другие – при загрузке и при работе программы. В принципе, программа может иметь несколько сегментов одного вида.
Рис. 1.5. Сегментация программы
Сегмент |
Регистры |
Что содержит |
Когда создается |
Сегмент команд |
CSсегментный, |
Программный код (операции, |
трансляция |
|
IPадрес команды |
операторы) |
|
Сегмент данных |
DS – сегментный |
Глобальные (статические) |
трансляция |
|
|
данные |
|
Сегмент стека |
SS – сегментный, |
Локальные данные функций, |
при загрузке |
Программирование – лекция 1 (лекции Стрикелевой Л.В.) |
14 |
|
|
SP– указатель стека |
«история» работы |
|
|
|
программы |
|
Динамическая |
DS – сегментный |
Динамические переменные, |
при загрузке, |
память |
|
создаваемые при работе |
выполнении |
|
|
программы |
|
Динамически |
CS– сегментный, |
Программный код |
при загрузке |
связываемые |
IP– адрес команды |
разделяемых библиотек |
|
библиотеки |
|
|
|
(DLL) |
|
|
|
Следующий элемент архитектуры тоже имеет отношение к внутреннему представлению программы – вирт уальное адресное прост ранст во (вирт уальная памят ь). Его идея состоит в том,
что каждая программа имеет свое, независимое от других, виртуальное адресное пространство (виртуальную память), в котором размещаются сегменты программы, определяются адреса и т.п. В процессоре имеется скрытая от программ система отображения виртуальных адресов на физические адреса., Вирт уальное адресное прост ранст во находится под управлением операционной системы и реализует защиту памяти программ, ее разделение (сегменты динамически связываемых библиотек), загрузку программы в память «по частям» и иллюзию наличия неограниченной памяти. Для нас из всего этого важно то, что внутренне представление программы в виртуальной памяти занимает все адресное пространство, как будто других программ и операционной системы в памяти нет вовсе.
Процесс исполнения программного кода
Процесс исполнения программного кода в общих чертах представлен на Рис.1.6. Действующими лицами этого процесса являются:
•программный код – последовательность команд, размещенная в сегменте кода (CS), на начало которого ссылается одноименный регистр процессора;
Рис. 1.6. Кодовое представление программы
•каждая команда имеет в сегменте свой относительный адрес (от начала сегмента), регистр процессора IP (Instruction Pointer) содержит адрес очередной выполняемой команды. В программировании на языках высокого уровня с IP ассоциируется очень важное понятие – т екущая т очка выполнения программы;
•команда представляет собой машинное слово, обычно переменной длины, и
Программирование – лекция 1 (лекции Стрикелевой Л.В.) |
15 |
|
состоит из нескольких полей. Обязательным полем является код операции, который указывает на выполняемое командой действие. Совокупность команд процессора называется сист емой команд. В системе команд обязательно присутствуют следующие виды операций:
o команды перемещения и обработ ки данныхвыполняют перенос данных между ячейками памяти и регистрами данных процессора, а также все действия по их обработке (mov, add, sub);
o команды проверки сост ояний (условий) проверяют результат выполнения операций, состояния регистров процессора, устройств ввода-вывода и т.п. (test); o команды условного и безусловного переходов определяют адрес следующей команды (выполняют переход в программе) в зависимости от результата проверки некоторого условия. Если условие выполняется, то происходит переход, иначе выполняется следующая за ней команда.
•вторым элементом команды являются операнды: в команде в явном или неявном виде должны содержаться адреса операндов; это могут быть регистры процессора, содержащие данные, и ячейки памяти;
•переменные, используемые в программы, при трансляции «становятся» областями памяти в различных сегментах данных (сегменты данных, стека, динамической памяти), где получают свои адреса. В командах, работающих с памятью, в том или ином виде имеется информация, позволяющая вычислить (или просто взять) этот адрес;
•в нашем примере большинство команд переноса и обработки данных являются двухадресными – результат операции совпадает с первым операндом (команду сложения add ax, 454 следует понимать как ax=ax+b);
•в нашем примере используется непосредст венная адресация для констант (их значение находится в самой программе, add ax, #10) и прямая адресация для ячеек памяти (в команде содержится их адрес, add ax, 454);
•в командах безусловного (jmp) и условного (jmi – «переход, если меньше нуля») должен быть определен адрес следующей команды: в нашем примере он задан в относительной форме – в виде смещения (расстояния) от следующей команды до той, куда производится переход.
Выполнение программы происходит, в общих чертах, таким образом:
•процессор, используя регистры CS:IP выбирает из памяти очередную команду и расшифровывает ее. После этого IP увеличивается и ссылается на следующую команду (в зависимости от длины текущей, например, IP=IP+3);
•если это команда переноса или перемещения данных, то процессор формирует адреса операндов в зависимости от способа адресации, после чего выполняет действия, указанные в команде;
•если это команда проверки условия, то проверяется указанный операнд, и устанавливаются признаки выполнения различных условий (равно 0, не равно 0, больше 0 и т.п.);
•если в команде условного перехода проверяемое условие выполняется, то программа «переходит» по адресу, содержащемуся в команде. В нашем примере это смещение из команды просто добавляется к IP (IP=IP+<смещение>). Иначе ничего не происходит и выбирается следующая команда.
Сравнивая систему команд компьютера с другими способами представления программ в известных технологиях программирования, можно заметить, что внутреннее представление
Программирование – лекция 1 (лекции Стрикелевой Л.В.) |
16 |
|