goto - с любимыми не расставайтесь, или break не тащит
Модератор: Модераторы
Seenkao
Наверно тогда тебе на асм.ру будешь сам себе и компилятором и оптимизатором.
Не надо иронии, вот твой коллега часто не знает что он пишет и что происходит, списывая все на мистику и какие то загадочные инки и деки.
Ну и заодно чтоб если много позже данный топик будет читать какой нибудь будущий студент\школьник, то получит правильный посыл.
Наверно тогда тебе на асм.ру будешь сам себе и компилятором и оптимизатором.
Не надо иронии, вот твой коллега часто не знает что он пишет и что происходит, списывая все на мистику и какие то загадочные инки и деки.
Ну и заодно чтоб если много позже данный топик будет читать какой нибудь будущий студент\школьник, то получит правильный посыл.
zub писал(а):тебе про фому ты про ерему. нет в нормально написанной программе многоярусных циклов for которые надо прерывать
Ну нукась нукась, как ты это себе представляешь ?
(Особенно в вообщем случае когда мы незнаем размерности матрицы заранее. )
Последний раз редактировалось Alex2013 30.10.2020 01:00:48, всего редактировалось 1 раз.
Да, забыл. Есть два, три и более вложенных цикла. И тут даже примера писать не надо. Вы не выйдите из циклов не сделав тонну ошибок, если не используете GoTo.
Да, можно обойтись и без GoTo. Что заставит в каждом вложенном цикле сохранять на одну переменную больше, а если нам надо все эти переменные сохранить (в какой момент произошло событие), то вложенные циклы решаются вызовом процедуры из процедуры... из процедуры... Результат такого действия, нагромождение кода: бесполезные Call-Ret; чтение-сохранение данных; учёт ситуации (дополнительные условия) - который должен был произойти сразу, но из-за нагромождения процедур, нам надо писать либо отдельную часть программы, по выходу из последней процедуры, либо постепенно делать проверки в каждой процедуре...
И, да!!! Не путать с РЕКУРСИЕЙ!!!
Добавлено спустя 1 минуту 35 секунд:
zub, поверь! Большинству ты советуешь верно! Но надо уточнять, что постарайтесь всё сделать без GoTo.
Да, можно обойтись и без GoTo. Что заставит в каждом вложенном цикле сохранять на одну переменную больше, а если нам надо все эти переменные сохранить (в какой момент произошло событие), то вложенные циклы решаются вызовом процедуры из процедуры... из процедуры... Результат такого действия, нагромождение кода: бесполезные Call-Ret; чтение-сохранение данных; учёт ситуации (дополнительные условия) - который должен был произойти сразу, но из-за нагромождения процедур, нам надо писать либо отдельную часть программы, по выходу из последней процедуры, либо постепенно делать проверки в каждой процедуре...
И, да!!! Не путать с РЕКУРСИЕЙ!!!
Добавлено спустя 1 минуту 35 секунд:
zub, поверь! Большинству ты советуешь верно! Но надо уточнять, что постарайтесь всё сделать без GoTo.
Последний раз редактировалось Seenkao 30.10.2020 01:04:34, всего редактировалось 2 раза.
Alex2013
Получи данные, проверь их, создай нужные структуры. Давай сосать из пальца не будем.
Единственное разумное занял Seenkao - я тут главный, за все плачу - делаю как хочу. Ок, делай, но других не учи плохому
Получи данные, проверь их, создай нужные структуры. Давай сосать из пальца не будем.
Единственное разумное занял Seenkao - я тут главный, за все плачу - делаю как хочу. Ок, делай, но других не учи плохому
Seenkao писал(а):zub, вы заурядный программист, который изучил программирование "вдоль и поперёк"! Вы всё знаете! Все алгоритмы вам известны! Я склоняю пред вами свою голову, Ваше Высочество!
В данном случае ирония немного хромает .. zub реально отличный перфекционист у которого есть чему поучится .
Alex2013, человек со стажем, не будет советовать плохого!
Я не про себя, я учусь и буду учится дальше. Невозможно всё знать, и, вероятно в какой-то из дискуссий, попадётся нужная информация, которая не сразу может дойти до любого из читающих.
Добавлено спустя 2 минуты 17 секунд:

(поправка! Большинство не те, кто давно занимается программированием, а большинство из тех, кто читает)
Я не про себя, я учусь и буду учится дальше. Невозможно всё знать, и, вероятно в какой-то из дискуссий, попадётся нужная информация, которая не сразу может дойти до любого из читающих.
Добавлено спустя 2 минуты 17 секунд:
постараюсь, забываю поправку на большинство делать...zub писал(а):Ок, делай, но других не учи плохому
(поправка! Большинство не те, кто давно занимается программированием, а большинство из тех, кто читает)
Последний раз редактировалось Seenkao 30.10.2020 00:54:16, всего редактировалось 1 раз.
zub писал(а):Получи данные, проверь их, создай нужные структуры.
Расшифровываю с "зубского" : Прочти одни и теже данные два раза . (Не спорю иногда так и приходится делать, но говорить, что это заведомо лучшее решение могут только "полные оптимисты" )
>>Прочти одни и теже данные два раза
Прочти данные в структуру близкую к формату хранения, проверь, преобразуй в формат удобный для использования.
естественно ничего делать 2 раза не надо и перегона больших данных туда сюда нужно стараться избегать
Добавлено спустя 9 минут:
>>да циклы рвут вдоль и поперёк, а не умеешь рвать их, значит не судьба.
ИМХО цикл фор стоит прерывать только если нужно свалиться, т.е. по исключению.
Иначе после прерывания захочется использовать цикловую переменную, а для этого уже лучше не for использовать. Ты ведь не используешь после гото из for цикловую переменную?
Прочти данные в структуру близкую к формату хранения, проверь, преобразуй в формат удобный для использования.
естественно ничего делать 2 раза не надо и перегона больших данных туда сюда нужно стараться избегать
Добавлено спустя 9 минут:
>>да циклы рвут вдоль и поперёк, а не умеешь рвать их, значит не судьба.
ИМХО цикл фор стоит прерывать только если нужно свалиться, т.е. по исключению.
Иначе после прерывания захочется использовать цикловую переменную, а для этого уже лучше не for использовать. Ты ведь не используешь после гото из for цикловую переменную?
Это, зачастую зависит от вложенности циклов. Если надо конкретный момент, то вероятно да. Зачастую другие переменные нужны, зависящие от тех, что использовались в цикле.
Всё надо смотреть в конкретном примере. В последнее время почти не было таких моментов. Но я так же уточняю, что в основном использую его для проверки работы кода. А использовать его в программе или нет, уже позже решаю.
В тестах - линейный код, а в программе наверняка разветвлённый. )))
Добавлено спустя 4 минуты 53 секунды:
Кусок кода, как раз линейный код использовал для проверки. Вариант далеко не лучший, но мне и не нужно было лучший вариант. Мне нужен был рабочий вариант.
Всё надо смотреть в конкретном примере. В последнее время почти не было таких моментов. Но я так же уточняю, что в основном использую его для проверки работы кода. А использовать его в программе или нет, уже позже решаю.
В тестах - линейный код, а в программе наверняка разветвлённый. )))
Добавлено спустя 4 минуты 53 секунды:
Код: Выделить всё
procedure MyTimer;
var
i: Integer;
label
jmping;
begin
// сейчас делаю мышь, но всё должно происходить относительно тачскрина
if NumMenu = TouchMenuGame1 then
begin
// if (M_BLEFT_DOWN and mouseUpDown) > 0 then
if mBUpDown(M_BLEFT_DOWN) then
begin
if ((Sqr(mouseX - TouchJoyRolling.Rolling.X) + Sqr(mouseY - TouchJoyRolling.Rolling.Y)) <= Sqr(TouchJoyRolling.Rolling.R)) then
begin
TouchJoyRolling.Rolling._x := mouseX;
TouchJoyRolling.Rolling._y := mouseY;
TouchJoyRolling.Rolling.bPush := 1;
TouchJoyRolling.Rolling.direction := m_Angle(TouchJoyRolling.Rolling.X, TouchJoyRolling.Rolling.Y, TouchJoyRolling.Rolling._x, TouchJoyRolling.Rolling._y);
goto jmping; // прыжка не должно быть, если будет опрашиваться несколько касаний
end
else
TouchJoyRolling.Rolling.bPush := 0;
// TouchJoyRolling.bPush := 0;
// TouchKey._keyPush := 0;
for i := 1 to TouchJoyRolling.count do
begin
if ((mouseX > TouchJoyRolling.OneButton[i].X) and (mouseX < (TouchJoyRolling.OneButton[i].X + TouchJoyRolling.Width)) and
(mouseY > TouchJoyRolling.OneButton[i].Y) and (mouseY < (TouchJoyRolling.OneButton[i].Y + TouchJoyRolling.Height))) then
begin
TouchJoyRolling.OneButton[i].bPush := 1;
keysDown[TouchJoyRolling.OneButton[i]._key] := True;
end
else begin
keysDown[TouchJoyRolling.OneButton[i]._key] := False;
TouchJoyRolling.OneButton[i].bPush := 0;
end;
end;
end;
end;
if NumMenu = TouchMenuGame2 then
begin
// это будет функция, которая будет возвращать результат - код нажатой(отжатой) клавиши, или, если ролик, то угол
// клавиатура будет возвращать код нажатой клавиши, как на клавиатуре
// множественный вызов не лучшее решение, но у клавиатуры должно быть не больше 2-х, 3-х касаний, поэтому на клавиатуру
// будет вводится ограничение, а на джойстики ограничения не будет, и надо будет делать запрос массивом касаний.
if (M_BLEFT_DOWN and mouseUpDown) > 0 then
begin
for i := 1 to 9 do
if i <> 5 then
begin
if ((mouseX > TouchJoy.BArrow[i].X) and (mouseX < (TouchJoy.BArrow[i].X + TouchJoy.Width)) and
(mouseY > TouchJoy.BArrow[i].Y) and (mouseY < (TouchJoy.BArrow[i].Y + TouchJoy.Height))) then
begin
TouchJoy.BArrow[i].bPush := 1;
keysDown[TouchJoy.BArrow[i]._key] := true;
end
else begin
TouchJoy.BArrow[i].bPush := 0;
keysDown[TouchJoy.BArrow[i]._key] := false;
end;
end;
// TouchJoy.bPush := 0; // типо ни чего не нажато
// TouchKey._keyPush := 0;
for i := 1 to TouchJoy.count do
begin
if ((mouseX > TouchJoy.OneButton[i].X) and (mouseX < (TouchJoy.OneButton[i].X + TouchJoy.Width)) and
(mouseY > TouchJoy.OneButton[i].Y) and (mouseY < (TouchJoy.OneButton[i].Y + TouchJoy.Height))) then
begin
TouchJoy.OneButton[i].bPush := 1; // нажата клавиша
keysDown[TouchJoy.OneButton[i]._key] := True; // прописываем нажатие клавиши
// TouchJoy.OneButton[i].b := i; // и номер нажатой клавиши
end
else begin
keysDown[TouchJoy.OneButton[i]._key] := False;
TouchJoy.OneButton[i].bPush := 0;
end;
end;
end;
end;
// здесь ещё надо производить отжатие!!! И отмечать, что клавиша уже нажата. Точнее, если нажал и не отжимал клавишу,
// то и нажать больше ни чего нельзя!!!
if NumMenu = TouchMenuKeySymb then
if (M_BLEFT_DOWN and mouseUpDown) > 0 then
begin
if (TouchKey.bPush and 1 > 0) then
goto jmping;
TouchKey.bPush := 1;
// сначала надо проверить все нажатые или отжатые стринговые клавиши.
for i := 35 to 45 do
begin
if ((mouseX > TouchKey.StringButton[i].X) and (mouseX < (TouchKey.StringButton[i].X + TouchKey.StringButton[i].Width)) and
(mouseY > TouchKey.StringButton[i].Y) and (mouseY < (TouchKey.StringButton[i].Y + TouchKey.Height))) then
begin
TouchKey._keyPush := i; // отмечаем для себя, какая клавиша нажата
if (i = _Rus) then
Continue; // пропускаем двойные клавиши.
// делаем вид, что клавиша нажата
TouchKeyDown(TouchKey.StringButton[i]._key);
if i = _CapsLock then
TouchKey.Flags := TouchKey.Flags xor keyboardCaps; // тут всё просто, выставляем флаг
if i = _Shift then
TouchKey.bPush := 128; // нажат шифт, можно нажимать другие клавиши
if i = _Latin then
TouchKey.Flags := TouchKey.Flags xor keyboardLatinRus; // флаг должен выставляться!!!
if i = _symb then
TouchKey.Flags := TouchKey.Flags xor keyboardSymbol; // флаг должен выставляться!!!
if i = _Insert then
TouchKey.Flags := TouchKey.Flags xor keyboardInsert;
goto jmping;
end;
end;
for i := 1 to TouchKey.count do
begin
if ((mouseX > TouchKey.OneButton[i].X) and (mouseX < (TouchKey.OneButton[i].X + TouchKey.OWidth)) and
(mouseY > TouchKey.OneButton[i].Y) and (mouseY < (TouchKey.OneButton[i].Y + TouchKey.Height))) then
begin
TouchKey._keyPush := i; // отмечаем для себя, какая клавиша нажата
TouchKeyDown(TouchKey.OneButton[i]._key); // код клавиши, не символ!!!
goto jmping;
end;
end;
TouchKey.bPush := 0; // если мы добрались до сюда, то ни какой клавиши нажато не было
end;
if NumMenu = TouchMenuKeyNumb then
if (M_BLEFT_DOWN and mouseUpDown) > 0 then
begin
TouchKeySymb.bPush := 1;
for i := 1 to TouchKeySymb.count do
begin
if ((mouseX > TouchKeySymb.OneDoubleButton[i].X) and (mouseX < (TouchKeySymb.OneDoubleButton[i].X + TouchKeySymb.OWidth)) and
(mouseY > TouchKeySymb.OneDoubleButton[i].Y) and (mouseY < (TouchKeySymb.OneDoubleButton[i].Y + TouchKeySymb.Height))) then
begin
TouchKeySymb._keyPush := i;
TouchKeyDown(TouchKeySymb.OneDoubleButton[i]._key);
goto jmping;
end;
end;
for i := 24 to 27 do
begin
if ((mouseX > TouchKeySymb.BArrow[i].X) and (mouseX < (TouchKeySymb.BArrow[i].X + TouchKeySymb.OWidth)) and
(mouseY > TouchKeySymb.BArrow[i].Y) and (mouseY < (TouchKeySymb.BArrow[i].Y + TouchKeySymb.Height))) then
begin
TouchKeySymb._keyPush := i;
TouchKeyDown(TouchKeySymb.BArrow[i]._key);
goto jmping;
end;
end;
for i := 36 to 44 do
Begin
if ((mouseX > TouchKeySymb.StringButton[i].X) and (mouseX < (TouchKeySymb.StringButton[i].X + TouchKeySymb.StringButton[i].Width)) and
(mouseY > TouchKeySymb.StringButton[i].Y) and (mouseY < (TouchKeySymb.StringButton[i].Y + TouchKeySymb.Height))) then
begin
TouchKeySymb._keyPush := i;
TouchKeyDown(TouchKeySymb.StringButton[i]._key);
if i = _Insert then
TouchKeySymb.Flags := TouchKeySymb.Flags xor keyboardInsert;
if i = _Shift then
TouchKeySymb.bPush := 128; // нажат шифт, можно нажимать другие клавиши
goto jmping;
end;
end;
TouchKeySymb.bPush := 0;
end;
jmping:
// твою меть!!! На джойстиках разрешено множественное нажатие!!! На клавиатуре нет...
if (M_BLEFT_UP and mouseUpDown) > 0 then
begin
if NumMenu = 2 then
begin
for i := 1 to 9 do
if i <> 5 then
begin
TouchJoy.BArrow[i].bPush := 0;
TouchKeyUp(TouchJoy.BArrow[i]._key);
end;
for i := 1 to TouchJoy.count do
begin
TouchJoy.OneButton[i].bPush := 0;
TouchKeyUp(TouchJoy.OneButton[i]._key);
// TouchKey._keyPush := 0; // по идее, вот не пофиг что тут стоит, если клавиша не нажата?
end;
end;
if NumMenu = 1 then
begin
TouchJoyRolling.Rolling.bPush := 0;
for i := 1 to TouchJoyRolling.count do
begin
TouchJoyRolling.OneButton[i].bPush := 0;
TouchKeyUp(TouchJoyRolling.OneButton[i]._key);
end;
end;
if NumMenu = 3 then
begin
// напоминаю, для шифта надо запомнить нажатие, что было сделано первым.
// надо будет просто проверять координаты нажатия и отжатия
if (TouchKey.bPush and 1) > 0 then
begin
if TouchKey._keyPush < 35 then
TouchKeyUp(TouchKey.OneButton[TouchKey._keyPush]._key)
else
begin
if keysDown[K_F2] then
begin
NumMenu := 4;
CreateTouchMenu(NumMenu);
end;
TouchKeyUp(TouchKey.StringButton[TouchKey._keyPush]._key);
end;
// TouchKey.bPush := 0;
end else
begin
TouchKeyUp(K_SHIFT);
end;
TouchKey.bPush := 0;
end;
if NumMenu = 4 then
begin
// напоминаю, для шифта надо запомнить нажатие, что было сделано первым.
// надо будет просто проверять координаты нажатия и отжатия
if (TouchKeySymb.bPush and 1) > 0 then
begin
if TouchKeySymb._keyPush < 24 then
TouchKeyUp(TouchKeySymb.OneDoubleButton[TouchKeySymb._keyPush]._key)
else
if TouchKeySymb._keyPush < 34 then
TouchKeyUp(TouchKeySymb.BArrow[TouchKeySymb._keyPush]._key)
else begin
if keysDown[K_F2] then
begin
NumMenu := 3;
CreateTouchMenu(NumMenu);
end;
TouchKeyUp(TouchKeySymb.StringButton[TouchKeySymb._keyPush]._key);
end;
// TouchKey.bPush := 0;
end else
begin
TouchKeyUp(K_SHIFT);
end;
TouchKeySymb.bPush := 0;
end;
end;
if NumMenu = 1 then
begin
if keysDown[K_A] = True then
begin
NumMenu := 2;
CreateTouchMenu(NumMenu);
end;
end;
if NumMenu = 2 then
begin
if keysDown[K_C] = True then
begin
NumMenu := 1;
CreateTouchMenu(NumMenu);
end;
end;
wnd_SetCaption(utf8_Copy('Touch Menu [FPS: ' + u_IntToStr(zgl_Get(RENDER_FPS)) + ']'));
mouse_ClearState;
key_ClearState;
end;
Кусок кода, как раз линейный код использовал для проверки. Вариант далеко не лучший, но мне и не нужно было лучший вариант. Мне нужен был рабочий вариант.
>>Если надо конкретный момент, то вероятно да
Я правильно понимаю что используете цикловую переменную после выхода из цикла?
Значение цикловой переменной не гарантируется вне цикла. поэтому такой код опасен, он может работать на данной платформе или на данной версии компилятора, но на следующей версии \ другой платформе вполне законно сломается
Я правильно понимаю что используете цикловую переменную после выхода из цикла?
Значение цикловой переменной не гарантируется вне цикла. поэтому такой код опасен, он может работать на данной платформе или на данной версии компилятора, но на следующей версии \ другой платформе вполне законно сломается
Возможно было такое. Но безусловный переход не влияет на регистры - это я точно знаю. И на содержимое в памяти тоже. Но, если учитывать, что множественные вложенные циклы, то вероятно мы просто потеряем большинство данных, если нам нужны именно они. Регистров на всё не хватит, а ссылки на данные могут сменится(циклы разорваны).
Этот вариант я не рассматривал! Видимо не приходилось сильно с этим бодаться. Благодарю за напоминание!
Этот вариант я не рассматривал! Видимо не приходилось сильно с этим бодаться. Благодарю за напоминание!
>>нет в нормально написанной программе многоярусных циклов for которые надо прерывать
Давайте уже закончим?
Это можно продолжать бесконечно.
Это можно продолжать бесконечно.
Провокационный вопрос знатокам генерируемого кода:
А вот внезапный выход из процедуры/функции изнутре n-раз вложенного цикла, это столь же плохо для "оптимизации", как goto изнутре n-раз вложенного цикла, или - фэншуй?
А вот внезапный выход из процедуры/функции изнутре n-раз вложенного цикла, это столь же плохо для "оптимизации", как goto изнутре n-раз вложенного цикла, или - фэншуй?
В теме, конечно, некоторые лютый бред пишут (привет @Alex2013), но, тем не менее:
— goto вряд ли портит оптимизацию, он в плане отслеживания control flow не отличается от того же break.
— У goto есть более-менее приемлемые применения:
По-моему, вариант с goto нагляднее. В C вместо него можно использовать проваливающийся case, в Паскале нет проваливающегося case и нужны либо goto, либо цикл.
— goto вряд ли портит оптимизацию, он в плане отслеживания control flow не отличается от того же break.
— У goto есть более-менее приемлемые применения:
- • goto &finally — если не хочется использовать try ... finally.
• goto break_outer — если не хочется выносить вложенный цикл в отдельную процедуру.
• goto again — если не хочется заворачивать весь повторяемый кусок кода в repeat until false.
Код: Выделить всё
{$mode objfpc} {$longstrings on} {$codepage utf8}
uses
SysUtils;
type
TState = record
stage: byte;
end;
TStageSet = set of byte;
function MultiStageProcess(var state: TState; pauseAtStages: TStageSet): boolean;
label stage0, stage1, stage2, stage3;
begin
case state.stage of
0: goto stage0;
1: goto stage1;
2: goto stage2;
3: goto stage3;
else raise Exception.Create('функция завершена');
end;
stage0:
inc(state.stage);
writeln('Раз.');
if state.stage in pauseAtStages then exit(false);
stage1:
inc(state.stage);
writeln('Два.');
if state.stage in pauseAtStages then exit(false);
stage2:
inc(state.stage);
writeln('Три.');
if state.stage in pauseAtStages then exit(false);
stage3:
inc(state.stage);
writeln('Четыре.');
exit(true);
end;
function MultiStageProcessWithoutGoto(var state: TState; pauseAtStages: TStageSet): boolean;
begin
repeat
case state.stage of
0:
begin
inc(state.stage);
writeln('Раз.');
end;
1:
begin
inc(state.stage);
writeln('Два.');
end;
2:
begin
inc(state.stage);
writeln('Три.');
end;
3:
begin
inc(state.stage);
writeln('Четыре.');
exit(true);
end;
else
raise Exception.Create('функция завершена');
end;
if state.stage in pauseAtStages then exit(false);
until false;
end;
var
state: TState;
begin
state.stage := 0;
repeat
if state.stage > 0 then writeln('---');
until MultiStageProcess(state, [2]);
writeln;
state.stage := 0;
repeat
if state.stage > 0 then writeln('---');
until MultiStageProcessWithoutGoto(state, [2]);
end.По-моему, вариант с goto нагляднее. В C вместо него можно использовать проваливающийся case, в Паскале нет проваливающегося case и нужны либо goto, либо цикл.
