goto - с любимыми не расставайтесь, или break не тащит

Любые обсуждения, не нарушающие правил форума.

Модератор: Модераторы

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение zub » 30.10.2020 01:33:29

Seenkao
Наверно тогда тебе на асм.ру будешь сам себе и компилятором и оптимизатором.

Не надо иронии, вот твой коллега часто не знает что он пишет и что происходит, списывая все на мистику и какие то загадочные инки и деки.
Ну и заодно чтоб если много позже данный топик будет читать какой нибудь будущий студент\школьник, то получит правильный посыл.
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Alex2013 » 30.10.2020 01:35:29

zub писал(а):тебе про фому ты про ерему. нет в нормально написанной программе многоярусных циклов for которые надо прерывать

Ну нукась нукась, как ты это себе представляешь ? :roll: Например читаешь "одномерные данные" в трехмерную матрицу и тут бабах ! Данные кончились (или сработало стоп условие "дальше пустота" ) ... И что тут можно РАЗУМНОГО кроме выхода сделать ?
(Особенно в вообщем случае когда мы незнаем размерности матрицы заранее. )
Последний раз редактировалось Alex2013 30.10.2020 02:00:48, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2926
Зарегистрирован: 03.04.2013 11:59:44

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Seenkao » 30.10.2020 01:42:10

Да, забыл. Есть два, три и более вложенных цикла. И тут даже примера писать не надо. Вы не выйдите из циклов не сделав тонну ошибок, если не используете GoTo.

Да, можно обойтись и без GoTo. Что заставит в каждом вложенном цикле сохранять на одну переменную больше, а если нам надо все эти переменные сохранить (в какой момент произошло событие), то вложенные циклы решаются вызовом процедуры из процедуры... из процедуры... Результат такого действия, нагромождение кода: бесполезные Call-Ret; чтение-сохранение данных; учёт ситуации (дополнительные условия) - который должен был произойти сразу, но из-за нагромождения процедур, нам надо писать либо отдельную часть программы, по выходу из последней процедуры, либо постепенно делать проверки в каждой процедуре...

И, да!!! Не путать с РЕКУРСИЕЙ!!!

Добавлено спустя 1 минуту 35 секунд:
zub, поверь! Большинству ты советуешь верно! Но надо уточнять, что постарайтесь всё сделать без GoTo. :)
Последний раз редактировалось Seenkao 30.10.2020 02:04:34, всего редактировалось 2 раз(а).
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение zub » 30.10.2020 01:44:13

Alex2013
Получи данные, проверь их, создай нужные структуры. Давай сосать из пальца не будем.
Единственное разумное занял Seenkao - я тут главный, за все плачу - делаю как хочу. Ок, делай, но других не учи плохому
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Alex2013 » 30.10.2020 01:45:05

Seenkao писал(а):zub, вы заурядный программист, который изучил программирование "вдоль и поперёк"! Вы всё знаете! Все алгоритмы вам известны! Я склоняю пред вами свою голову, Ваше Высочество!

В данном случае ирония немного хромает .. zub реально отличный перфекционист у которого есть чему поучится . :idea:
Alex2013
долгожитель
 
Сообщения: 2926
Зарегистрирован: 03.04.2013 11:59:44

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Seenkao » 30.10.2020 01:48:21

Alex2013, человек со стажем, не будет советовать плохого! :idea:
Я не про себя, я учусь и буду учится дальше. Невозможно всё знать, и, вероятно в какой-то из дискуссий, попадётся нужная информация, которая не сразу может дойти до любого из читающих. :)

Добавлено спустя 2 минуты 17 секунд:
zub писал(а):Ок, делай, но других не учи плохому
постараюсь, забываю поправку на большинство делать... :)
(поправка! Большинство не те, кто давно занимается программированием, а большинство из тех, кто читает)
Последний раз редактировалось Seenkao 30.10.2020 01:54:16, всего редактировалось 1 раз.
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Alex2013 » 30.10.2020 01:52:56

zub писал(а):Получи данные, проверь их, создай нужные структуры.

Расшифровываю с "зубского" : Прочти одни и теже данные два раза . (Не спорю иногда так и приходится делать, но говорить, что это заведомо лучшее решение могут только "полные оптимисты" ) :wink:
Alex2013
долгожитель
 
Сообщения: 2926
Зарегистрирован: 03.04.2013 11:59:44

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение zub » 30.10.2020 01:58:30

>>Прочти одни и теже данные два раза
Прочти данные в структуру близкую к формату хранения, проверь, преобразуй в формат удобный для использования.
естественно ничего делать 2 раза не надо и перегона больших данных туда сюда нужно стараться избегать

Добавлено спустя 9 минут:
>>да циклы рвут вдоль и поперёк, а не умеешь рвать их, значит не судьба.
ИМХО цикл фор стоит прерывать только если нужно свалиться, т.е. по исключению.
Иначе после прерывания захочется использовать цикловую переменную, а для этого уже лучше не for использовать. Ты ведь не используешь после гото из for цикловую переменную?
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Seenkao » 30.10.2020 02:22:54

Это, зачастую зависит от вложенности циклов. Если надо конкретный момент, то вероятно да. Зачастую другие переменные нужны, зависящие от тех, что использовались в цикле.

Всё надо смотреть в конкретном примере. В последнее время почти не было таких моментов. Но я так же уточняю, что в основном использую его для проверки работы кода. А использовать его в программе или нет, уже позже решаю.

В тестах - линейный код, а в программе наверняка разветвлённый. )))

Добавлено спустя 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;

Кусок кода, как раз линейный код использовал для проверки. Вариант далеко не лучший, но мне и не нужно было лучший вариант. Мне нужен был рабочий вариант. :)
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение zub » 30.10.2020 02:28:28

>>Если надо конкретный момент, то вероятно да
Я правильно понимаю что используете цикловую переменную после выхода из цикла?
Значение цикловой переменной не гарантируется вне цикла. поэтому такой код опасен, он может работать на данной платформе или на данной версии компилятора, но на следующей версии \ другой платформе вполне законно сломается
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Seenkao » 30.10.2020 02:34:53

Возможно было такое. Но безусловный переход не влияет на регистры - это я точно знаю. И на содержимое в памяти тоже. Но, если учитывать, что множественные вложенные циклы, то вероятно мы просто потеряем большинство данных, если нам нужны именно они. Регистров на всё не хватит, а ссылки на данные могут сменится(циклы разорваны).

Этот вариант я не рассматривал! Видимо не приходилось сильно с этим бодаться. Благодарю за напоминание!
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение zub » 30.10.2020 02:43:50

>>нет в нормально написанной программе многоярусных циклов for которые надо прерывать
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение Seenkao » 30.10.2020 02:50:23

Давайте уже закончим?
Это можно продолжать бесконечно.
Seenkao
энтузиаст
 
Сообщения: 502
Зарегистрирован: 01.04.2020 03:37:12

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение SSerge » 30.10.2020 06:36:12

Провокационный вопрос знатокам генерируемого кода:

А вот внезапный выход из процедуры/функции изнутре n-раз вложенного цикла, это столь же плохо для "оптимизации", как goto изнутре n-раз вложенного цикла, или - фэншуй? :?:
SSerge
энтузиаст
 
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: goto - с любимыми не расставайтесь, или break не тащит

Сообщение runewalsh » 30.10.2020 10:12:44

В теме, конечно, некоторые лютый бред пишут (привет @Alex2013), но, тем не менее:

goto вряд ли портит оптимизацию, он в плане отслеживания control flow не отличается от того же break.

— У goto есть более-менее приемлемые применения:
    goto &finally — если не хочется использовать try ... finally.
    goto break_outer — если не хочется выносить вложенный цикл в отдельную процедуру.
    goto again — если не хочется заворачивать весь повторяемый кусок кода в repeat until false.
Ещё одно интересное применение: continuation, функция с возможностью приостановки и продолжения для реализации async-await-подобной парадигмы.
Код: Выделить всё
{$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, либо цикл.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 578
Зарегистрирован: 27.04.2010 00:15:25

Пред.След.

Вернуться в Потрепаться

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 19

Рейтинг@Mail.ru