Введение
Тип парадигмы программирования в информатике
В информатике императивное программирование — это парадигма программирования, использующая операторы, изменяющие состояние программы. Подобно тому, как повелительное наклонение в естественных языках выражает команды, императивная программа состоит из команд, предназначенных для выполнения компьютером. Императивное программирование фокусируется на описании того, как программа работает шаг за шагом, а не на высокоуровневых описаниях ожидаемых результатов. Этот термин часто используется в противопоставление декларативному программированию, которое фокусируется на том, что программа должна выполнить, не указывая все детали реализации результата.
Процедурное программирование
Процедурное программирование — это тип императивного программирования, в котором программа строится из одной или нескольких процедур (также называемых подпрограммами или функциями). Эти термины часто используются как синонимы, но использование процедур оказывает значительное влияние на внешний вид и структуру императивных программ. Интенсивное процедурное программирование, при котором изменения состояния локализованы внутри процедур или ограничены явными аргументами и возвращаемыми значениями, является формой структурированного программирования. Начиная с 1960-х годов, структурированное и модульное программирование в целом продвигались как методы повышения поддерживаемости и общего качества императивных программ. Концепции, лежащие в основе объектно-ориентированного программирования, стремятся расширить этот подход. Процедурное программирование можно рассматривать как шаг в направлении декларативного программирования. Программист часто может понять, просто взглянув на имена, аргументы и типы возвращаемых значений процедур (и соответствующие комментарии), что должна делать конкретная процедура, не обязательно изучая детали её реализации. При этом, программа в целом остаётся императивной, поскольку в значительной степени определяет последовательность выполняемых операторов и порядок их выполнения.
Основания и основы императивного программирования
Парадигма программирования, используемая для создания программ для почти всех компьютеров, обычно следует императивной модели. Аппаратное обеспечение цифровых компьютеров предназначено для выполнения машинного кода, который является родным для компьютера и обычно написан в императивном стиле, хотя для некоторых архитектур, таких как Lisp-машины, существуют компиляторы и интерпретаторы низкого уровня, использующие другие парадигмы. С точки зрения низкого уровня состояние программы определяется содержимым памяти, а операторы – инструкциями на машинном языке компьютера. Императивные языки программирования более высокого уровня используют переменные и более сложные операторы, но всё равно следуют той же парадигме. Рецепты и контрольные списки процессов, хотя и не являются компьютерными программами, также представляют собой знакомые концепции, схожие по стилю с императивным программированием: каждый шаг – это инструкция, а состояние хранится в физическом мире. Поскольку основные идеи императивного программирования интуитивно понятны и непосредственно реализованы в аппаратном обеспечении, большинство языков программирования используют императивный стиль. Операторы присваивания в императивной парадигме выполняют операцию с данными, расположенными в памяти, и сохраняют результаты в памяти для последующего использования. Императивные языки программирования высокого уровня, кроме того, позволяют вычислять сложные выражения, состоящие из комбинации арифметических операций и вызовов функций, и присваивать полученное значение памяти. Операторы циклов (такие как циклы while, do-while и for) позволяют многократно выполнять последовательность операторов. Циклы могут выполнять содержащиеся в них операторы заданное количество раз или повторять их до тех пор, пока не будет выполнено определённое условие. Операторы условного ветвления позволяют выполнять последовательность операторов только при выполнении определённого условия. В противном случае операторы пропускаются, и выполнение продолжается со следующего оператора. Операторы безусловного перехода позволяют передать управление в другую часть программы. К ним относятся переход (называемый goto во многих языках), оператор switch и вызов подпрограммы, процедуры или функции (который обычно возвращает управление следующему оператору после вызова). На ранних этапах разработки языков программирования высокого уровня введение блоков позволило создавать программы, в которых группу операторов и объявлений можно рассматривать как единый оператор. Это, наряду с введением подпрограмм, позволило выражать сложные структуры посредством иерархического разложения на более простые процедурные структуры. Многие императивные языки программирования (такие как Fortran, BASIC и C) являются абстракциями языка ассемблера.
История императивных и объектно-ориентированных языков
Самыми ранними императивными языками были машинные языки первоначальных компьютеров. В этих языках инструкции были очень простыми, что облегчало аппаратную реализацию, но затрудняло создание сложных программ. FORTRAN, разработанный Джоном Бэкусом в International Business Machines (IBM) начиная с 1954 года, стал первым крупным языком программирования, устранившим препятствия, создаваемые машинным кодом при разработке сложных программ. FORTRAN был компилируемым языком, который позволял использовать именованные переменные, сложные выражения, подпрограммы и многие другие возможности, которые сейчас распространены в императивных языках. В последующие два десятилетия было разработано множество других основных императивных языков программирования высокого уровня. В конце 1950-х и 1960-х годов ALGOL был разработан для более удобного представления математических алгоритмов и даже использовался в качестве целевого языка операционной системы для некоторых компьютеров. MUMPS (1966) довел императивную парадигму до логического предела, отказавшись от каких-либо операторов и полагаясь исключительно на команды, вплоть до того, что команды IF и ELSE стали независимыми друг от друга и связывались только внутренней переменной с именем $TEST. COBOL (1960) и BASIC (1964) были попытками сделать синтаксис программирования более похожим на английский язык. В 1970-х годах Паскаль был разработан Никлаусом Виртом, а C — Деннисом Ричи, работавшим в Bell Laboratories. Вирт продолжил разработку Modula 2 и Oberon. По заказу Министерства обороны США Жан Ичбиах и команда Honeywell приступили к разработке Ada в 1978 году после четырехлетнего проекта по определению требований к языку. Спецификация была впервые опубликована в 1983 году, с последующими редакциями в 1995, 2005 и 2012 годах. В 1980-х годах наблюдался резкий рост интереса к объектно-ориентированному программированию. Эти языки были императивными по стилю, но добавляли возможности для поддержки объектов. В последние два десятилетия XX века появилось множество таких языков. Smalltalk 80, первоначально задуманный Аланом Кеем в 1969 году, был выпущен в 1980 году исследовательским центром Xerox Palo Alto (PARC). Основываясь на концепциях другого объектно-ориентированного языка — Simula (который считается первым в мире объектно-ориентированным языком программирования, разработанным в 1960-х годах), Бьярне Строструп разработал C++, объектно-ориентированный язык, основанный на C. Разработка C++ началась в 1979 году, а первая реализация была завершена в 1983 году. В конце 1980-х и 1990-х годах наиболее заметными императивными языками, использующими объектно-ориентированные концепции, были Perl, выпущенный Ларри Уоллом в 1987 году; Python, выпущенный Гидо ван Россумом в 1990 году; Visual Basic и Visual C++ (включавшие Microsoft Foundation Class Library (MFC) 2.0), выпущенные Microsoft в 1991 и 1993 годах соответственно; PHP, выпущенный Расмусом Лердорфом в 1994 году; Java, разработанный Джеймсом Гослингом (Sun Microsystems) в 1995 году, JavaScript, разработанный Бренданом Айхом (Netscape), и Ruby, разработанный Юкихиро "Матц" Мацумото, оба выпущенные в 1995 году. Microsoft .NET Framework (2002) является императивным по своей сути, как и его основные целевые языки VB.NET и C#, работающие на нем; однако Microsoft F#, функциональный язык, также работает на нем.
С
Язык программирования C (1973) получил свое название, потому что язык BCPL был заменен на B, а AT&T Bell Labs назвала следующую версию "C". Его целью было создание операционной системы UNIX. C – относительно небольшой язык, что упрощает написание компиляторов. Его развитие шло параллельно с развитием аппаратного обеспечения в 1980-х годах. Одна область называется сегментом инициализированных данных, где хранятся переменные, объявленные со значениями по умолчанию. Другая область называется блоком, начатым сегментом, где хранятся переменные, объявленные без значений по умолчанию. Переменные, хранящиеся в глобальной и статической областях данных, получают свои адреса во время компиляции. Они сохраняют свои значения на протяжении всего времени работы процесса. Глобальная и статическая области хранят глобальные переменные, объявленные вне (выше) функции main. Глобальные переменные видны функции main и любой другой функции в исходном коде. С другой стороны, объявления переменных внутри main, других функций или в блоках, ограниченных фигурными скобками { }, являются локальными переменными. Локальные переменные также включают формальные параметры функций. Параметры функций заключаются в круглые скобки в определении функции и служат интерфейсом для нее. Локальные переменные, объявленные с префиксом static, также хранятся в глобальной и статической областях данных. Переменные, помещенные в стек, заполняются сверху вниз и называются автоматическими переменными. Как и для стека, адреса переменных в куче устанавливаются во время выполнения. Происходит ошибка нехватки памяти, когда указатель кучи и указатель стека пересекаются. C предоставляет библиотечную функцию malloc для выделения памяти в куче. Заполнение кучи данными – это дополнительная операция копирования. Переменные, хранящиеся в куче, эффективно передаются функциям с использованием указателей. Без указателей весь блок данных пришлось бы передавать функции через стек.