лекции (2008) (by Михайлишин Алексей_ Жбанков Денис_ Щербинин Виктор_ Чеботарев Павел) (1160831), страница 6
Текст из файла (страница 6)
результат в любом случае будет false). В языке-предтече Ады предлагалось ввестидва вида логических операций – обычные и ленивые (and then, or else). В результате ленивость былазафиксирована. В C логические операции также ленивые. С точки зрения оптимизации ираспараллеливания нужно минимизировать побочные эффекты операций.Первоначально, под потоком управления понимали передачу выполнения на любую точку кода (GOTO).Если передашь не туда – твоя проблема.
Так и было в Фортране. Ситуация стала меняться, когда сталиписать более сложные программы (ОС, например). 1967 – Э.Дейкстра опубликовал статью о вреде GOTO –это была одна из самых популярных статей по CS. Фактически, эта статья положила началу новомунаправлению – структурированное программирование (однако, прижился перевод структурное).Появилось понятие структуры управления, т.е. есть некоторые «черные ящики», которые передают другдругу данные, управление и у каждого есть только один вход и выход.Управляющие структуры:• ветвленияo односторонние (if B then S1;)o двусторонние (if B then S1 else S2;)Существует проблема замыкания (два if подряд – не понятно, какой else, к какому if) – этосинтаксическая неоднозначность. Проблемы была решена в пользу ближайшего if.
Используйтеоператорные скобки и все будет хорошо. В некоторых языках (Ада, М-2, VB) решили проблему подругому – там есть определенные терминанты (endif, end), и нет составных операторов.•••циклысоставной операторвызов подпрограммы / возвраты (call, return)[lect16] Есть две основные управляющие структуры - ветвление и циклы.I) ВетвленияОператор ветвления на 2 направления – if. Основная проблема - проблема вложенности.if B1 thenif B2 thenS2elseS3В языках появляется составной оператор - частный случай блока. Он применяется там, где по синтаксисуподходит 1 оператор, а требуется несколько. Отличие от блока - в блоке могут появляться локальныепеременные.
В языке паскаль блок - объявление, за которым следует составной оператор.объявленияbeginоператорыendADA, Modula-2, Bash (B-Shell), Оберон - используют схему явного закрытия операторов.Проблема вложенности решена:if B1 thenS11; S12; S13;end ifif B thenS1elseS2endЧем мы вынуждены платить за явное закрытие? В некоторых случаях надо употреблять многовариантныеразвилки.B1 -> S1;... -> ...Bn - >Sn;Такие развилки могут моделироваться через много вложенных if ... then .. else.if B1 thenS1elseif B2 thenS2elseif B3 thenS3...Но человеку трудно воспринимать такие структуры.
Корректная запись такой конструкции (на си):if (B1)S1else if (B2)S2else if (B3)S3...elseSn+1Но в некоторых языках в конце придется написать еще много "end if", что неудобно. Поэтому в язык надоспециально добавить оператор многовариантного ветвления.В языке Ада есть оператор elsif, в М-2 - ELIFif B1 thenSeg1{elsif Bi thenSegi}elseSegN+1endifОбщий оператор выбораcase Expr ofописание вариантовendВариантыконстанта: операторИзначально Вирт не предусмотрел действия, если ни одно значение не подходит. Но позже в паскале быладобавлена такая конструкция (else оператор).В М-2:CASE EXPR OFсписок вариантов |[ELSEоператоры]ENDВозможны и диапазоны:конст1..конст21,3,5..10,12Т.о.
семантика везде одинакова, синтаксис варьируется. Оператор переключателя (в Си):switch (expr) SСемантика: вычисляется значение выражения expr. Затем выполняется поиск нужной метки.case 1:case2: //Если expr == Ci, то делается goto Ci.Распространенная ошибка:case 1:a = i; // после первого case нужен break;case 2:...В языке Java синтаксис остался тем же, хотя оператор перехода там отсутствует вообще.
Слово goto тамзарезервировано. Если не написать break после case, компилятор выдаст ошибку (в С# так же). Еслизначение не входит в список констант, то нужна метка default (действия по умолчанию).II) Операторы циклаwhile B do Srepeat S1; S2; ... Sn; until BВ общем случае выход из цикла может быть в начале, в конце, в любом месте цикла.
Таким образом,должна быть специальная конструкция выхода из середины цикла.Модула-2:WHILE B DO ... ENDREPEAT .... UNTIL BLOOP ... END //бесконечный цикл,параллельного программирования)выходтолькопоEXIT(актуаленвзадачахАда: всего 3 разновидности циклаwhile, loop, forЕсть оператор exit:• укороченная форма - exit;• полная форма - when усл-е => exit;Си:•••while (B) S;do S while (B);forbreak - оператор выходаcontinue - оператор продолженияВ Ада, Си, Модула-2, Оберон - есть оператор выхода из функции - return. В Ада в качестве "break"используется оператор exit.имя:цикл или переключательbreak (имя) - выход из того цикла или переключателя, которыйпомечен меткой"имя"Цикл FORЦикл for всегда можно смоделировать циклом while.Паскаль:for v:=l1 to(downto) l2 do SМодула 2:FOR v:= E1 TO E2 [STEP N] DO ..
END1988 Оберон, 1993 Оберон-2 - цикл for вернулся.Ада:for v in диапазон loop...end loop;for i in A'RANGE loopfor i in A'FIRST..A'LAST loop...Замечание: в языке Ада переменную i не надо объявлять.В Си++ индекс можно объявлять прямо внутри цикла, и его область действия ограничивается этим циклом.for (int i=0; i<N; i++) SС появлениям языков C# и Java ситуация изменилась, например, нужно проходить циклом по коллекциям.Потребовалось контролировать диапазон индекса:for(int i=0; i< A.GetLength(P); i++).. A[i] // понятно, что i не может превзойти Length(P)Коллекция - обобщение массивов - просто набор элементов. Появилась специальная конструкиця дляобработки коллекций: foreachforeach (T o in C ) Sforeach (int x in a) s+=x;С помощью такого перебора нельзя модифицировать коллекцию, но просмотр становится эффективным.Этот оператор появился в C# с самого начала, а в Java только с 2005 года.Java:for (T o: C)Timertaskcancel();/////collection<TimerTask> c;for (TimerTask in c)t.cancel();Что мы не учли в этой главе: оператор entry, select (Ада) - для параллельного программирования.[lect18]Способы передачи параметров:1) по значению2) по результату3) по значению результата4) по имени5) по ссылке1)-3) применяются в случае, когда передаются небольшие данные, иначе накладные расходы слишкомвелики.
Thunk – переходник.Как это реализовано в языках:C - по значениюC++ - по значению + по ссылке, причем можно передавать константные объектыvoid f( const T& ); //константная ссылкаболее того, предполагается что при передачи без "const" объект обязательно должен изменяться в процессеобработкиvoid f(T) ; //по значениюPascal, Modula-2, Oberon-2 - по значению, по ссылке (параметры-переменные).
Способ передачи поссылке обеспечивает полный доступ к объекту.Ada - способ передачи параметров не указывается при передачеprocedure P(x:in T; y:out TT; z:inout T);x меняться не может, y,z - могут. При этом компилятор может выбрать соотв. семантику. Он может выбратьспособы 1),2),3),5). В Ada-95 вернулись к способу, который так или иначе реализован во всех другихязыках.Procedure P(x,y:out T)beginx = ....;raise ERROR;end PA:T;P(A,A)Если передаем по ссылке и происходит исключение, то значение A меняется.
Работа программы можетзависеть от компилятора, и это плохо. В ада-95 есть только 2 способа передачи - по значению и по ссылке.Java - все передается по значению, реально же простые типы передаются по значению (in семантика), аобъекты - по ссылке (inout семантика).Проблема - для простых типов данных - только in семантика, т.е. нельзя поменять в процедуре значениевнешней простой переменной. На первый взгляд это недостаток.
Но есть такое понятие как "побочныйэффект" - изменение в процессе работы процедуры значений глобальных объектов или фактическихпараметров. В случае изменения внешней переменной получается, что основным назначением процедурыявляется побочный эффект. Не рекомендуется менять значение глобальных объектов в процессе работыпроцедур. В современных ООП, таких как Java и C# вообще невозможно существование каких-тоглобальных объектов.В java.lang для каждого простого типа данных существует класс-обертка.Пример:int a;Integer v = a;f(v); //здесь мы можем менять v, т.к. он передается по ссылке.a = v+1; // обратная распаковкаvoid f(Integer v) {v = -1;}C# изначально проектировался как "моноязык".
По умолчанию все параметры передаются по значению,параметры типа объект - по ссылке. Есть 2 модификатора ref и out, которые реализуют передачупараметра по ссылке.void f(ref int a) { a = -1; }int i = 0;f(i); //ошибка, компилятор скажет что нужно добавить reff(ref i); //правильно. Эта особенность улучшает документированность кода.ref/out семантика может применяться к любым объектам, в т.ч. и к ссылкамvoid g(ref X y) {y = new X();}X a;g(ref a); // ошибка, неопределенная ссылка. (ссылка передается по ссылке)Delphiprocedure P(a:X);a f();a = X.create();Ввод-вывод, переменный список параметровprintf("%d %d=%s", a, b+1, str)параметры переменной длины:va_listva_startva_nextva_endprintf - небезопасная, но очень популярная функция.
До сих пор ее часто используют в c++printf("count=%d\n", i);Oberon:InOut.WriteString("count=");InOut.WriteInt(i);InOut.Writeln;В современных языках Java и C#params - модификатор последнего формального параметра.void f(params int[]integers); // теперь у функции может быть произвольный списокпараметров, но либо целого типа, либо приводимого к немуфункция write должна выводить любые типы, поэтому:write(string format,params Object[] objects); //все типы приводимы к ObjectОбратим внимание на следующую функцию:void f(int[] integers); //существен. разница, аргументом может быть только массивв C# 3.0 введено ключевое слово var - переменная с выводимым именем типа (не бестиповая!)ListVewItem i = new ListViewItem();var i = new ListViewItem; // то же самое что и вышеТакие нововведения связаны с тем, что C# разрабатывался с учетом интеграции с БД, другими языками.Создатели Java не пошли по этому пути, и обошлись без добавления новых ключевых слов.Функцию с переменным числом параметром можно записать так:void f(int ...
integers) { // новая лексема "..."int r=0;for(int i: integers) {r+=i;}return i;}//функция вывода может быть описана так:void write(string fmt; Object ... objs);III) Подпрограммные типы данных•передача подпрограмм как параметров других подпрограммВирт ввел еще 2 особых вида параметров - формальные параметры-процедуры, формальные параметрыфункции.Delphi, Modula-2, Oberon - введен подпрограммный тип данныхTYPE PROCINT=PROCEDURE(INTEGER);VAR P:PROCINT; // можно присваивать процедуры, имеющие 1 параметр типа INTEGERTYPE F=PROCEDURE(REAL):REAL;PP = PROCEDURE(VAR T);До появления ООП подпрограммные типы рассматривались как средства передачи параметров в другиеподпрограммы.В языке ада-83 не было подпрограммных типов.В языке ада-95 появился программный тип (т.к.