Как известно из курса дисциплины «Информатика», под программой в этой предметной области понимается логически упорядоченная последовательность команд, необходимых для управления компьютером, т.е. выполнения им конкретных операций. Программирование же, как род деятельности сводится к созданию последовательности команд, необходимой для решения определенной задачи с помощью ЭВМ, а люди, обученные процессу их составления с помощью языков программирования (программированию) называются программистами [8].
Процесс поиска ошибок в программе называется тестированием, а процесс устранения ошибок — отладкой.
Появление первых компьютеров породило программирование как науку. Разрабатывались первые математические теории обработки информации, средства доказательства правильности программ, оптимизации кода, создания эффективных компиляторов, формального тестирования и т. д. Затем, с появлением универсальных языков программирования третьего поколения, эти аспекты стали менее актуальными — исследования шли и идут в основном в области автоматической генерации исходных текстов и повышения эффективности компиляторов. При этом программирование одновременно становится и искусством - миллионы людей, не имевших специального образования, получили возможности применять компьютеры для решения собственных прикладных задач, что потребовало от них мастерства создавать правильно работающие программы. Искусством программирование остается и сегодня для профессиональных разработчиков и любителей, создающих программы в одиночку или в небольших компаниях, где все решает индивидуальное мастерство.
Как следует из логики программирования, сначала всегда разрабатывается алгоритм действий, а потом он записывается на одном из таких языков. В итоге получается текст программы — полное, законченное и детальное описание алгоритма на языке программирования.
Процессор компьютера — это большая интегральная микросхема. Все команды и данные он получает в виде электрических сигналов, которые можно представить как совокупности нулей и единиц, то есть числами. Разным командам соответствуют разные числа. Поэтому реально, на физическом уровне программное обеспечение, под управлением которого работает процессор, представляет собой последовательность чисел, называемую машинным кодом.
В то же время, управлять компьютером нужно в определенной последовательности или говорят - по определенному алгоритму. Следовательно, алгоритм — это точно определенное описание способа решения задачи в виде конечной (по времени) последовательности действий.
Описать даже простую такую последовательность действий компьютера в машинном коде весьма сложно, причем эта сложность резко возрастает с увеличением трудоемкости решения нужной задачи. Поэтому сегодня для представления алгоритма в виде, понятном компьютеру, служат так называемые языки программирования.
Языки программирования — это специальные искусственные языки. От естественных они отличаются ограниченным числом «слов», значение которых понятно транслятору, и очень строгими правилами записи команд (операторов). Совокупность подобных требований образует синтаксис языка программирования, а смысл каждой команды и других конструкций языка - его семантику. Нарушение формы записи программы приводит к тому, что ЭВМ не может понять назначение оператора и выдает сообщение о синтаксической ошибке, а правильно написанное, но не отвечающее алгоритму использование команд языка приводит к семантическим ошибкам (называемые еще логическими ошибками или ошибками времени выполнения).
Разные типы процессоров имеют разные наборы команд. Если язык программирования ориентирован на конкретный тип процессора и учитывает его особенности, то он называется языком программирования низкого уровня. В данном случае «низкий уровень» не значит «плохой». Имеется в виду, что операторы языка близки к машинному коду и ориентированы на конкретные команды процессора.
Языком самого низкого уровня является язык ассемблера, который просто представляет каждую команду машинного кода, но не в виде чисел, а с помощью символьных условных обозначений, называемых мнемониками. Однозначное преобразование одной машинной инструкции в одну команду ассемблера называется транслитерацией. Так как наборы инструкций для каждого модели процессора отличаются, конкретной компьютерной архитектуре соответствует свой язык ассемблера, и написанная на нем программа может быть использована только в этой среде.
С помощью языков низкого уровня создаются очень эффективные и компактные программы, так как разработчик получает доступ ко всем возможностям процессора. С другой стороны, при этом требуется очень хорошо понимать устройство компьютера, затрудняется отладка больших приложений, а результирующая программа не может быть перенесена на компьютер с другим типом процессора. Подобные языки обычно применяют для написания небольших системных приложений, драйверов устройств, модулей стыковки с нестандартным оборудованием, когда важнейшими требованиями становятся компактность, быстродействие и возможность прямого доступа к аппаратным ресурсам. В некоторых областях, например в машинной графике, на языке ассемблера пишутся библиотеки, эффективно реализующие требующие интенсивных вычислений алгоритмы обработки изображений.
Языки программирования высокого уровня значительно ближе и понятнее человеку, нежели компьютеру. Особенности конкретных компьютерных архитектур в них не учитываются, поэтому создаваемые программы на уровне исходных текстов легко переносимы на другие платформы, для которых создан транслятор этого языка. Разрабатывать программы на языках высокого уровня с помощью понятных и мощных команд значительно проще, а ошибок при создании программ допускается гораздо меньше.
С помощью языка программирования создается еще не совсем готовая программа, а только ее текст, описывающий ранее разработанный алгоритм. Чтобы получить работающую программу, надо этот текст оттранслировать, т.е. либо автоматически перевести в машинный код (для этого служат программы-компиляторы) и затем использовать отдельно от исходного текста, либо сразу выполнять команды языка, указанные в тексте программы (этим занимаются программы-интерпретаторы).
Итак, интерпретатор берет очередной оператор языка из текста программы, анализирует его структуру, транслирует этот фрагмент в некоторое промежуточное представление или даже машинный код и затем сразу исполняет. Только после того как текущий оператор успешно выполнен, интерпретатор перейдет к следующему. При этом если один и тот же оператор должен выполняться в программе многократно, интерпретатор всякий раз будет выполнять его так, как будто встретил впервые. Вследствие этого, программы, в которых требуется осуществить большой объем повторяющихся вычислений, могут работать медленно. Кроме того, для выполнения такой программы на другом компьютере там также должен быть установлен аналогичный интерпретатор — ведь без него текст программы является просто набором символов,
По-другому, можно сказать, что интерпретатор моделирует некую виртуальную вычислительную машину, для которой базовыми инструкциями служат не элементарные команды процессора, а операторы языка программирования.
Компиляторы полностью обрабатывают весь текст (или, говорят - исходный код) программы. Они просматривают его в поисках синтаксических ошибок (иногда несколько раз), выполняют определенный смысловой анализ и затем автоматически переводят (транслируют) на машинный язык, т.е. — генерируют машинный код. Нередко при этом выполняется оптимизация с помощью набора методов, позволяющих повысить быстродействие программы (например, с помощью инструкций, ориентированных на конкретный процессор, путем исключения ненужных команд, промежуточных вычислений и т.д.). В результате законченная программа получается компактной и эффективной, работает в сотни раз быстрее программы, выполняемой с помощью интерпретатора, и может быть перенесена на другие компьютеры с процессором, поддерживающим соответствующий машинный код.
В реальных современных системах программирования технологии компиляции и интерпретации, как правило, перемешаны. Так, например, в процессе отладки программа может выполняться по шагам, а результирующий код не обязательно будет сразу машинным. Он даже может быть исходным кодом, написанным на другом языке программирования, или представлен промежуточным машиннонезависимым кодом абстрактного процессора, который в различных компьютерных архитектурах станет выполняться с помощью интерпретатора или компилироваться в соответствующий машинный код.
Итак, в самом общем случае для создания программы на языке программирования высокого уровня необходимо написать исходный текст программы, проверить его на отсутствие синтаксических ошибок и перевести в машинный код. При этом если будут обнаружены синтаксические ошибки, то результирующий код создавать, очевидно, не имеет смысла.
На этом этапе уже возможно получение готовой программы, но чаще всего в ней либо не хватает некоторых компонентов, либо исходный текст большой программы разбит, как правило, на модули (файлы с исходными текстами), потому что хранить все тексты в одном файле неудобно. Поэтому транслятор обычно выдает промежуточный (объектный) код каждого модуля в виде двоичного файла со специальным стандартным расширением (например - * .obj или *.tpu), которые затем надо объединить в одно целое.
Кроме того, к ним надо добавить машинный код фрагментов программы (подпрограмм), реализующих различные стандартные функции (например, вычисляющих математические функции Sin(x) или Ln(x)). Такие функции, обычно, содержатся в библиотеках (файлах со стандартным расширением .lib), которые поставляются вместе с компилятором. При чем, сгенерированный код модулей и подключенные к нему стандартные функции надо объединить в одно целое с учетом требований операционной системы, то есть получить на выходе программу, отвечающую определенному формату.
Поэтому объектный код, полученный после транслятора, обрабатывается специальной программой — редактором связей или сборщиком, который выполняет связывание объектных модулей и машинного кода стандартных функций, находя их в библиотеках, и формирует на выходе работоспособное приложение - исполнимый код для конкретной платформы,
Если по каким-то причинам один из объектных модулей или нужная библиотека не обнаружены (например, неправильно указан каталог с библиотекой), то сборщик сообщает об ошибке и готовой программы не получается.
Исполнимый код — это законченная программа, которую можно запустить на любом компьютере, где установлена операционная система, для которой эта программа создавалась. Как правило, итоговый файл имеет расширение *.exe или *.com.
Таким образом, в стандартную поставку любой системы программирования, как правило, входят как минимум три компонента,