лекции (2008) (Фингеров Александр_ Кононов Алексей_ Кузин Сергей), страница 8
Описание файла
Документ из архива "лекции (2008) (Фингеров Александр_ Кононов Алексей_ Кузин Сергей)", который расположен в категории "". Всё это находится в предмете "языки программирования" из 7 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Онлайн просмотр документа "лекции (2008) (Фингеров Александр_ Кононов Алексей_ Кузин Сергей)"
Текст 8 страницы из документа "лекции (2008) (Фингеров Александр_ Кононов Алексей_ Кузин Сергей)"
ADDRESS
Идея была следующая – был оператор, который и передавал управление: PROCEDURE TRANSFER (VAR COR1, COR2:ADDRESS). Теперь необходимо запоминать кроме адреса возврата еще и состояние локальных переменных (в стеке). При вызове оператора мы должны восстановить весь локальный контекст. Есть адрес в процедурной памяти, где сохраняется все. Перед тем как запустить программу необходимо инициализировать ее контекст. Такая процедура называлась NEWPROCESS(P:PROC; VAR COR:ADRESS (адрес в котором сохраняется); N:INTEGER (сколько памяти нужно отвести подпрограмме на контекст – это знает только сам программист)). Таким образом вызов довольно низкоуровневый. Это говорит о том, что Клаусу Вирту не удалось сделать простую и низкоуровневую процедуру для вызова сопрограмм. Была еще некая процедура IOTRANSFER, один из аргументов был номер некоторого прерывания – процедура вызывается в тот момент, когда происходит некоторое прерывание.
В современных языках отсутствует, а введено понятие параллельных процессов. Поэтому возникает вопрос введения этого механизма в базис языка. Тогда встает проблема, связанная с производительностью при работе со средствами параллелизма уже встроенными в систему.
Пункт 2. Передача данных в процедуры. Механизм передачи параметров.
- при возврате из функции
- при передаче параметров
- через глобальные переменные
Нас будет интересовать второй пункт.
- in_out семантика передачи параметров (отвечает на вопрос - что именно происходит)
- способы/механизмы передачи параметров (отвечает на вопрос - как именно)
CALLER CALLEE
In ->
Out <-
In_Out <-> нам нужно и входное значение, и мы можем поменять значение соответствующего параметра.
Механизм передачи параметров это реализация. А семантика – передача параметров с точки зрения ЯП, не вникая в его реализацию. В ЯП высокого уровня мы будем говорить именно о семантике передачи параметров.
Использование ключевых слов in, out, inout:
Function ABS(x: in REAL) return REAL; (мы не можем поменять значение x.)
Procedure MAX_INT (A : in ARR, max : out real, index : out integer); (max, index – должно быть присвоено некоторое значение при выходе)
Procedure SWAP (x,y : inout T) (и читается, и меняется значение)
При этом в современных ЯП фиксируется именно механизм передачи параметров.
-
по значению
-
по результату
-
по значению/результату
-
по имени
-
по ссылке
Есть фактический и формальный параметр. При передаче параметров в момент вызова функции происходит связывание формальных параметров с фактическими. Есть 2 момента связывания – момент вызова и момент возврата.
Связывание по ссылке – это связывание в момент вызова. Связь, в таком случае, не разрывается до момента выхода. Под формальными параметрами понимаются некоторые переменные, которые почти эквиваленты локальным переменным. Самый простой способ их расположение – на регистре процессора, в стеке.
В первой реализации Фортрана формальные параметры располагались в области видимости, а реализовались в сегменте данных. Формальные параметры это в общем случае локальные параметры.
-
Что такое передача по значению? Фактический параметр копируется в формальный при вызове. (В Си и Java только по значению)
-
В фактический параметр копируется значение формального параметра при возврате. (передача параметров по результату.)
-
Фактический параметр копируется в формальный при вызове и формальный в фактический при возврате. (В некоторых вариантах Фортрана это использовалось)
-
Передача параметров по имени. Похоже на макроподстановку, правда более сложный. Фактический параметр подставляется на место соответствующего формального параметра. Например, есть массив А, передаем A[i]. Везде подставляется A[i]. Если изменится i, то изменится и значение.
-
По ссылке(адресу) – адрес объекта передается по значению.
С точки зрения семантики нам достаточно 1-3. Но с точки зрения эффективности – нет. Например, передача массивов.
Procedure swap(a,b)
Intger a,b; (ключевого слово value нет, значит передается по имени)
Begin
Integer tmp;
Tmp := a; a:=b; b:=tmp;
End;
Это не работает. Почему? Посмотрим, первый меняется a. Представим
Array 1..N of integer
I:=1;
Swap(A[i], i); - это работает правильно.
Swap(I, A[i]); - это не работает, так меняется i, а после этого A[от нового значения i].
Лекция 17
In, out, inout семантика
-
По значению.
-
По результату.
-
По значению и результату.
-
По имени.
-
По ссылке.
Почти во всех языках программирования реализован способ передачи по значению. (С – по значению.)
С++ - по значению + по ссылке (для ссылок). Дает возможность передачи константных объектов, константность обеспечивает неизменность значения в пределах блока. Если объект объявлен как const, то это гарантирует, что он не изменит свое значение. Если объект объявлен глобальный – то это просто напросто константа. А если сопоставлен параметру, то это означает не то, что параметр константен, а то, что передаваемый объект не изменяется. Если функция объявлена как void f (T&); - то функции нельзя передать константный объект, даже если он реально не изменяется. Это передача объектов out/inout, для in следует использовать void f(const T&). Если void f (T); - то передаем по значению.
Pascal, Modula-2, Oberon (Oberon2) – по значению, по ссылке (параметры переменные). Способ передачи по ссылке обеспечивает полный доступ, таким образом, в этих языках нет защиты на запись.
Ада – перед параметром может стоять одно из ключевых слов – in, out, inout:
Procedure P (x:in T (менять нельзя); y:out TT (может меняться, при этом изменится фактический параметр); z:inout T(может меняться, при этом изменится фактический параметр, при этом требуется, чтобы было значение у параметра)).
В Аде 95 вернулись к способу, который так или иначе реализован почти во всех языках. Они либо реализуют передачу по значению, либо по ссылке.
Procedure P(x,y: out T) is
Begin
X:= …; raise ERROR; Y:=….;
End P
P(A,A);
Если параметры передаются по ссылке, то значение А меняется, а если по результату – то не меняется.
Java – по значению. По значению передаются простые типы данных, а все остальные объекты – по ссылке. Для всех простых in-семантика, а для остальных – inout-семантика. Если стоит final (например, final int y) – это значит, что менять значение нельзя. Таким образом, можем проконтролировать inout-семантику. Например, хотим написать функцию, которая меняет значение параметра. На первый взгляд, нельзя написать такую функцию, если параметр простого типа. В языке есть функции и процедуры, а начиная с языка Алгол-60 это разница исчезла. Процедура или функция различаются наличием побочного эффекта. Основным назначением процедуры является побочный эффект. Сразу возникает вопрос, а что же функция? Побочный эффект в функции это не приятная вещь. В итоговом варианта Ады остались только такие виды функций и процедур:
Function F(x: T) return T;
Procedure P(x: out T, inout T);
А такой вид :
Procedure FF(x: inout T); return T;
был исключен.
В Java для каждого типа данных есть класс-обертка (в пакете java.lang).
void integer f (intrger V){ v= -1;}
Int a;
Integer v= a; (значение a завернуто в переменную v)
f (v);
a= v + 1; (обратная распаковка)
В C# все параметры по умолчанию передаются по значению. Но есть модификаторы ref и out, которые реализуют передачу параметров по ссылке.
Void f(ref int a) {a =-1;} (передача по ссылке)
От ref параметра требуется семантика inout. Однако если передадим неинициализированную переменную, то компилятор выдаст ошибку.
Void g(ref X y)
{
Y = new X();
X a;
}
g (ref a); - скажет, что не соответствует семантике inout , так как a должна быть инициализирована. Лучше объявить функцию g следующим образом:
void g(out X y);
В языке Delphi :
Procedure P ([var] a: X);
Список аргументов переменной длины.
Printf (“%d, %d = %s”, a ,b+1, str);
Сишные макросы для функций с переменным числом параметров:
va_list
va_start
va_next
va_end
Недостаток - ненадежность , если, например, str – не строка. И можем получить ошибку сегментацию памяти, или программа вообще продолжит работу.
У класса cstring есть формат format(“ ”, …); Несмотря на то, что есть функции << и >> в С++, программисты на этом языке все равно продолжают использовать функции языка Си.
Например, на языке Оберон вызов функции языка Си printf(“Count = %s\n”, i); будет соответствовать следующий код: