Файл: Основные правила работы с функциями: примеры и ограничения использования функций в различных языках программирования.pdf
Добавлен: 29.03.2023
Просмотров: 260
Скачиваний: 1
СОДЕРЖАНИЕ
1.1. Определение функции, основные понятия
1.3. Преимущества и недостатки использования функций
2. Анализ языков программирования для приведения примеров использования функций
2.1. Языки низкого и высокого уровня
2.2. Типизированные и не типизированные языки программирования
2.3. Выбор языков программирования для приведения примеров использования функций
3. Примеры и ограничения использования функций
3.1. Примеры и ограничения использования функций в C++
3.2. Примеры и ограничения использования функций в Assembler
3.3. Примеры и ограничения использования функций в JavaScript
Тип передаваемых параметров можно задавать и явно (см. рисунок 25).
Рисунок 25. Процедура на ассемблере с указанием типа передаваемых параметров
В обоих случаях следует отметить макрос ret, который заканчивает работу функции возвращает управление управляющей программе, которая и вызвала функцию. Важно отметить, что макрос ret может быть использован для возвращения числа, например, суммы или произведения параметров, – это необязательно при использовании макроса, но возможно [11].
Вызов процедуры можно осуществить несколькими способами – как напрямую по имени процедуры, так при вызове участка памяти, в котором сохранен адрес процедуры [1]. На рисунке 26 представлены разные вариации вызова процедуры. Следует отметить, что во всех случаях процедура вызывается при помощи макроса call, который по сути является простым переходом на адрес, в котором хранится процедура – с одной поправкой: он сохраняет в памяти адрес текущей инструкции. Это сделано для того, чтобы после выполнения процедуры программа вернулась ровно в то место, откуда была вызвана функция – макрос ret читает сохраненный в памяти адрес и совершает переход [1].
Для функций в ассемблере есть несколько путей получения данных, это:
- передача параметров через регистры;
- передача параметров через общую область памяти;
- передача аргументов через стек.
Проще всего передавать данные через регистр – не требуется дополнительных переменных, выделения памяти, функция или процедура сразу может обратиться по нужному адресу памяти и получить данные. Вместе с тем, количество регистров невелико, как и размеры регистров, и необходимо всегда помнить, какая информация в каком регистре находится [1].
Рисунок 26 Разные вариации вызова процедуры на Ассемблер
Общая область памяти получается, когда используется атрибут common. Общей области памяти нужно имя – при выполнении инструкции, которые принадлежат одной и той же общей области памяти, будут физически размещены на соседних сегментах памяти, таким образом организуя общее адресное пространство, к которому в пределах области памяти можно будет быстро получить доступ. Недостаток этого подхода в том, что никак нельзя проконтролировать состояние данных в отдельный момент времени – нет защиты данных от разрушения и нет никаких правил доступа к данным. Если несколько процессов выполняется одновременно, то неизвестно, какой из них в какой момент времени и каким образом изменил информацию, находящуюся в общей области памяти.
Чаще всего используется передача данных через стек. Стек – это своеобразная «стопка» памяти, в которую укладываются данные. Получить данные обратно можно только с вершины стека.
В ассемблере микропроцессор имеет особые регистры для работы со стеком – ESS для «дна» стека, ESP для вершины стека, а также EBP на случай, если нужен произвольные доступ к стеку [1]. Пример процедуры с аргументами в стеке рассмотрен на рисунке 27.
Рисунок 27 Пример процедуры с аргументами в стеке на Ассемблер
Стек при этом выглядит так, как показано на рисунке 28.
Рисунок 28. Стек
В начале программы была обозначена архитектура процессора, для которого предназначены инструкции, а также обозначено, что размер одного элемента стека – четыре байта. Затем описана процедура proc_1, которая, используя регистр «дна» стека ESP и регистр произвольного доступа EBP получает доступ к данным в стеке «снизу вверх» вместо того, чтобы брать элементы последовательно «сверху вниз». Процедура main записывает в стек три числа и затем вызывает процедуру proc_1 [11].
3.3. Примеры и ограничения использования функций в JavaScript
Рассмотрим основные способы записи и работы с функциями в JavaScript.
В JavaScript существует 2 способа объявления функций. В первом случае функция объявляется с использованием ключевого слова function, после которого указывается имя функции и круглые скобки. Имя функции может содержать буквы, цифры, нижнее подчеркивание и знак доллара. В круглых скобках могут быть указаны названия параметров функции, отделенные друг от друга запятой [2]. Внутри функции параметры ведут себя как локальные переменные. За круглыми скобками располагаются фигурные скобки. В фигурных скобках содержится тело функции. Для возвращения значения внутри функции используется ключевое слово return. Если не указано конкретное возвращаемое значение, то функция возвращает undefined. return останавливает выполнение функции, то есть любой код, написанный после выражения с return никогда не выполнится [10].
На рисунке 29 приведен пример объявления функции умножения (параметры – a,b, в теле функции происходит возвращение их произведения). На рисунке 30 приведен пример вызова пустой функции, которая возвращает undefined, так как отсутствует return с другим значением.
Рисунок 29. Пример объявления функции на JavaScript
Рисунок 30. Пример вызова пустой функции, которая возвращает undefined
Во втором случае функцию можно объявить через функциональное выражение. В таком случае функция является выражением и ее результат присваивается куда-либо, например, переменной. Таким образом можно определить как обычную функцию, так и анонимную функцию. Функции, объявленные через функциональное выражение, не могут быть использованы перед объявлением, в то время как функции, объявленные первым способом – могут [10]. На рисунке 31 приведен пример объявления анонимной функции с помощью функционального выражения. На рисунке 32 приведен пример объявления именованной функции с помощью функционального выражения.
Рисунок 31. Пример объявления анонимной функции с помощью функционального выражения
Рисунок 32. Пример объявления именованной функции с помощью функционального выражения
Для более краткой записи функционального выражения используют стрелочные функции. Стрелочные функции могут быть только анонимными. Стрелочные функции записываются следующим образом: сначала в круглых скобках указываются параметры через запятую, затем следует оператор «=>», далее в фигурных скобках идет тело функции [2]. Пример стрелочной функции изображен на рисунке 33.
Рисунок 33. Пример стрелочной функции
Для того, чтобы вызвать функцию, нужно указать ее имя, и параметры в круглых скобках. Если параметров нет, то оставить пустые круглые скобки. Важно отметить, что круглые скобки являются оператором, который непосредственно вызывает функцию. Если указать имя функции без круглых скобок, то вернется сама реализация функции, а не ее возвращаемое значение [2]. Пример вызова обычной функции приведен на рисунке 34. На рисунке 35 приведен пример вызова стрелочной функции. При вызове стрелочной функции важно отметить, что в качестве названия функции указывается имя переменной, которой была присвоена эта функция.
Рисунок 34. Пример вызова обычной функции
Рисунок 35. Пример вызова стрелочной функции
В JavaScript, так же как и в С++, например, есть области видимости. Локальная переменная, объявленная внутри функции, видна только в пределах этой функции. На рисунке 36 объявлена функция, внутри которой объявлена локальная переменная i. Внутри этой функции можно использовать переменную i, но при попытке использовать ее вне функции, выскакивает ошибка.
Если вне функции была объявлена глобальная переменная, то она тоже будет доступна внутри функции. На рисунке 37 вне функции объявлена глобальная переменная globalVar. При попытке ее использования внутри функции func ошибки не происходит.
Если мы объявили локальную переменную в одной функции, то она не будет видна в другой функции. На рисунке 38 в функции func1 объявлена локальная переменная i. При попытке использования переменной i в функции func2 выскакивает ошибка [10].
Понятие области видимости рассматривается не только в рамках функции, но и в рамках циклов и условий. Если локальная переменная объявлена внутри условия, которое находится внутри функции, то за пределами этого условия в функции переменная не будет видна [10]. На рисунке 39 внутри условия объявлена локальная переменная i. Несмотря на то, что она объявлена внутри функции, при попытке ее использования вне условия выскакивает ошибка.
Рисунок 36. Пример использования локальной переменной вне функции
Рисунок 37. Пример использования глобальной переменной внутри функции
Рисунок 38. Пример использования локальной переменной одной функции в другой
Рисунок 39. Пример использования локальной переменной условия внутри функции и вне условия
В JavaScript параметрам функции можно задавать начальные значения. Для этого нужно после имени параметра через равно присвоить начальное значение [10]. На рисунке 40 параметрам функции умножения заданы начальные значения: 5 и 2. При вызове функции без указания значений параметров функция возвращает 10, то есть произведение начальных значений.
Рисунок 40. Пример задания начальных значений параметрам функции
В JavaScript есть возможность объявлять функцию внутри другой функции. В таком случае вызвать вложенную функцию можно только внутри функции, в которой она объявлена [2]. На рисунке 41 приведен пример вложенной функции. На рисунке 42 приведен пример использования вложенной функции вне области видимости.
Рисунок 41. Пример вложенной функции
Рисунок 42. Пример использования вложенной функции вне области видимости
Таким образом, мы рассмотрели основные особенности использования функций в таких языках программирования, как Assembler, С++ и JavaScript.
Языки программирования со строгой типизацией (C++) имеют более громоздкую запись функций за счет того, что все типы данных должны быть определены явно, а также все операции над данными должны проводиться с учетом того, что данные разных типов во многих случаях сочетать нельзя.
Языки с динамической типизацией (JavaScript) имеют более простую и короткую запись функций, и сами функции в них априори универсальны, но за это преимущество приходиться расплачиваться, во-первых, быстродействием в работе программы, поскольку каждый раз типы данных анализируются прямо при выполнении кода, и, во-вторых, сложностью отслеживания данных в программе - поскольку четких ограничений нет, неизвестно, данные какого типа поступили в функцию и данные какого типа из нее вернулись.
Нетипизированные языки, как правило, отличаются наилучшей скоростью работы в силу того, что корректность данных программными средствами попросту не отслеживается, и все проверки являются ответственностью программиста, что, соответственно, крайне усложняет программирование на языках подобного рода.
Заключение
В данной работе решены все поставленные задачи.
Было определено понятие функции, обозначены ее основные характеристики, выделены достоинства и недостатки функций. Был сделан вывод о том, что достоинств использования функций гораздо больше, чем недостатков.
Также была кратко рассмотрена классификация языков программирования. На основе анализа классификации были выбраны языки для приведения конкретных примеров и ограничений использования функций.
Было наглядно показано, что для каждого языка программирования в вопросе функций имеются свои тонкости. Основными критериями, по которым можно судить о функциях, можно назвать: способы работы с памятью - передачу и возвращение параметров, доступ к глобальным данным; способы именования, реализации и вызова функций - допускаются ли одинаковые имена и как в таком случае выбирается функция для вызова, нужно ли именовать функцию отдельно, где можно или нужно располагать объявление и реализацию функции, можно ли разделять объявление и реализацию.