goto vs break & continue
    , Кроха-сын пришел к отцу и спросила кроха: "goto - это хорошо?"
  ![]()  | 
Наши проекты:
 Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту  | 
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS | 
| [216.73.216.5] | 
 
 | 
		
  | 
    Правила раздела:
  | Страницы: (32) « Первая ... 7 8 [9] 10 11 ... 31 32 ( Перейти к последнему сообщению ) | 
    goto vs break & continue
    , Кроха-сын пришел к отцу и спросила кроха: "goto - это хорошо?"
  | 
         
         
         
          
           Сообщ.
           #121
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата JoeUser @  Как-то, так: ... Но все равно - это не тепичный алгоритм для GOTO, нет возвратов в ветви предыдущих вычислений. Много времени прошло с момента написания этого "робота", помницца и не все реализовано было (как-то, зависание на время формирования ответа серверной частью, возвраты от пустого ответа, на повторный прием ответа и пр.). Тем не менее - в том что я написал, ИМХО, "чтение" кода и сопоставление с блок-схемой проще, нежели в твоих разбиениях на области в виде функций. Без паллитры и карандаша с бумагой не разбересся. У меня "что видно, то и написано". Это в твоих переходах без поллитры не разберёшься. =) Qraizer правильно сказал про КА. ![]() ![]() type StateFn func() StateFn func Start() StateFn {     if !flagPhase {         return Exec     }     if flagNeedSend {         SendRequest()         return nil     }     if flagWait {         return nil     }     if flagNeedExec {         return Exec     }     if flagNecessity {         CreateRequest()         CreateWaitingFlag()         return nil     }     if flagWaitReply {         AcceptReply()         if !accepted {             return nil         }         if reply {             return SO         }         return ExecFlag     }     if !recieveInfExists || recieveInfOverdue {         CreateNecessityFlag()         return Exec     }     if recieveInfOverdueFinish {         return SO     }     Accept()     if updates {         return ExecFlag     }     return nil } func SO() StateFn {     SendSORequest()     CreateFlag()     return nil } func ExecFlag() StateFn {     // Create exec flag     return Exec } func Exec() StateFn {     if !execPhase {         return nil     }     if flagBuilding {         CreateRequest()         return Start     }     if flagExec {         Execute()     }     return nil } func main() {     for f := Start(); f != nil; f = f() {     } }  | 
    
| 
         
         
         
          
           Сообщ.
           #122
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
          С философской точки зрения, метки нужны там, где отсутствует структурное прогарммирование, например, на ассемблере, если код не выносится в функции, а пишется одной портянкой, то вызов функции заменяется goto, который вырождается в short jump или long jump. Это экономит и стек, так как никакие регистры не бэкапятся (выталкиваются) в стек и заново не перезагружаются данными. Причем, такое применение может быть как оптимизацией по скорости, так и по объему кода. 
        
      И совершенно верно замечено, что рефакторить такой код геморно. Так что, опять же, с философской точки зрения, могу предположить, что в Си goto появилась как следствие "понижения" уровня языка до ассемблерного уровня, когда можно кодить "байт в байт", используя язык высокого уровня. Чем, например, был весьма хорош Turbo C 2.0 (и компилил тоже пушечно). И все эти техники неиспользования промежуточных переменных типа: ![]() ![]() {   i = f(x);   return i; } лучше переписать как: ![]() ![]() {   return f(x); } и еще масса всяческих олдскульных штучек... Так как в первом случае значение функции, которое во времена i8086 обычно вычислялось только в AX(AH,AL), сначала пересылается куда-то в память, а потом возвращается обратно в AX (где по факту уже присутствует), и только потом вызывается RET... А сейчас и регистры стали внутри проца равноправнее, и винты толще, так что оптимизация by size тоже уже на грани удаления из компилятора напрочь... Сейчас никто (то есть, я в частности) asm не рефакторит, поэтому и смысла в goto в высокоуровневых языках уже нет. Но его отсутствие нарушит стандарт языка. А несовместимость со стандартом гораздо страшнее. ![]() Поэтому goto по-прежнему будет присутствовать, и его по-прежнему мало кто будет использовать, и это будет тоже очень правильно. И оптимизация by size тоже будет живее всех живых.  | 
    
| 
         
         
         
          
           Сообщ.
           #123
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата p1qb0d @  А я (см. первое сообщение темы) бы сказал, что вот бывает, что надо смотаться из двойного или тройного цикла, и тогда приходится городить лишний огород из переменных и т.п., либо просто сделать goto на выход и всё. Так что зависимость от ассемблера сомнительна. Так что, опять же, с философской точки зрения, могу предположить, что в Си goto появилась как следствие "понижения" уровня языка до ассемблерного уровня, когда можно кодить "байт в байт", используя язык высокого уровня.     | 
    
| 
         
         
         
          
           Сообщ.
           #124
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Славян @  А я (см. первое сообщение темы) бы сказал, что вот бывает, что надо смотаться из двойного или тройного цикла, и тогда приходится городить лишний огород из переменных и т.п., либо просто сделать goto на выход и всё. Так что зависимость от ассемблера сомнительна.  ![]() Это называется костыль и лень. Когда лень писать хороший качественный код, иногда люди начинаются писать говнокод. Вот как раз это тот описываемый тобой случай - говнокода. Что мешает тебе не городить 3 вложеных цикла? А обойтись дополнительной функцией, которая сделает твой код более читабельным, понятным и сопровождаемым? Добавлено Кстати а еще можно все писать в одной функции main, а нахрена нам другие функции? есть же волшебный goto, а блоки можно отделять коментариями, например както так: ![]() ![]() /*******************************************************************************/ ... /*******************************************************************************/ ... /*******************************************************************************/  | 
    
| 
         
         
         
          
           Сообщ.
           #125
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата KILLER @  Что мешает тебе не городить 3 вложеных цикла? А обойтись дополнительной функцией, которая сделает твой код более читабельным, понятным и сопровождаемым?  Это религия какая-то. Запросто может быть так, что три цикла гораздо читабельней, чем огород с вызовом функций.  | 
    
| 
         
         
         
          
           Сообщ.
           #126
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата OpenGL @   Это религия какая-то. Запросто может быть так, что три цикла гораздо читабельней, чем огород с вызовом функций.   Цитата KILLER @  Циклы бывают большие и сложные. Работают со многими данными. Пересылать весь их огород в функцию - и есть костыль, непонятно для чего. Что мешает тебе не городить 3 вложеных цикла?     | 
    
| 
         
         
         
          
           Сообщ.
           #127
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Славян @  Ладно выйти, а если войти?  ... вот бывает, что надо смотаться из двойного или тройного цикла, и тогда приходится городить лишний огород из переменных и т.п., ...  | 
    
| 
         
         
         
          
           Сообщ.
           #128
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Qraizer @  Мне ни разу такого не попадалось. Но так, сходу, и проблем со входом при наличии goto не вижу. А без него - точно такой же гемор с излишними плясками с переменными да условиями. Ладно выйти, а если войти?     | 
    
| 
         
         
         
          
           Сообщ.
           #129
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата OpenGL @  Это религия какая-то. Запросто может быть так, что три цикла гораздо читабельней, чем огород с вызовом функций. Это не религия, 2 вложеных цикла - еще терпимо и нормально, а три и более - запутывают читающего код, а если там еще и goto, то и вовсе сбивает с толку. Если тебе так нужно запилить три цикла вложеных с возможностью выхода из третьего, оформи их в отдельную функцию/метод и ливай по return из них. Какие проблемы? Я видел функции по 5 тысяч строк кода - это читать не возможно в принципе, там и по три вложеных цикла было и по четыре. Как по мне, лучше сделать несколько мелких функций, чтобы было понятно и прозрачно, чем шаманить трехэтажные циклы. Добавлено Цитата Славян @  Циклы бывают большие и сложные. Работают со многими данными. Пересылать весь их огород в функцию - и есть костыль, непонятно для чего.  ![]() Приведи пример такого костыля плз, я хочу посмотреть. Добавлено Цитата Qraizer @  Ладно выйти, а если войти?  Зачем? Добавлено Вообще писать можно как угодно и что угодно. Ну вот возьмет чел, напишет свою прогу в 100 000 строк тупо в функции Main, и она будет работать. Что он неверно сделал? Да все он верно сделал. Какое вам дело до того как он пишет? Религия чтоль не позволяет 100 000 строк в функции main запилить? Вот так вот и выглядят ваши аргументы со стороны. А на деле, эта религия мне помогает избежать кучи ошибок, и когда я открываю свой код через год - то я сходу понимаю что там написано. В отличии, если бы там были трехэтажные циклы и метки - такой код открываешь через месяц и начинаешь репу чесать и заного изучать что же я там имел ввиду - делая такие нетривиальные телодвижения. Добавлено Плюс ко всему, есть мнение, что чем больше у тебя будет осознанных слов в проге - тем легче она будет восприниматься и читаться. В случае с трехэтажными циклами - их меньше, и можно легко запутаться, никто не будет называть счетчик больше 5-6 букв, особенно если он часто используется в теле цикла. С функциями эта проблема решаема, т.к. мало кто называет функции в 1-2 буквы. И программа становится более читабельной.  | 
    
| 
         
         
         
          
           Сообщ.
           #130
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата KILLER @  Пример с тремя сложными циклами со многими переменными, переписанный на "вызов функции с табуном аргументов"=костыль?.. Приведи пример такого костыля плз, я хочу посмотреть.     | 
    
| 
         
         
         
          
           Сообщ.
           #131
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата Славян @  Пример с тремя сложными циклами со многими переменными, переписанный на "вызов функции с табуном аргументов"=костыль?..  ![]() Ну по твоему видимо да: Цитата Славян @  Пересылать весь их огород в функцию - и есть костыль Ок, приведи пример некостыля Цитата Славян @  с тремя сложными циклами со многими переменными Я просто хочу посмотреть, если я туда вставлю вызов функции - действительно хуже станет или нет.  | 
    
| 
         
         
         
          
           Сообщ.
           #132
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата KILLER @  Допустим так:Ок, приведи пример  некостыля... Я просто хочу посмотреть, если я туда вставлю вызов функции - действительно хуже станет или нет. ![]() ![]() int GetBestChessPos( void ) {    int count1[20];    float terVer[8][8], pokaz;    char superVertical[8];    ...    // заполняем все массивы для работы    // ...    // ниже = расчёт    for( int row=0; row<8; row++)       for( int col=colA; col<colH; col++)       {          pokaz += ...;          if( ... ) terVer[2][5] *= ...;          // испытываем воздействие          if( count1[15] + (int)pow(terVer[3][4] + terVer[2][5], pokaz) > count1[2] ) // опасное положение!            if( superVertical[2]<3 ) // мат нам грядёт              goto LBL_matPrideHanaBude;       }     ...   LBL_matPrideHanaBude:    // попытка рискнуть:    ... }  | 
    
| 
         
         
         
          
           Сообщ.
           #133
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата KILLER @  Если тебе так нужно запилить три цикла вложеных с возможностью выхода из третьего, оформи их в отдельную функцию/метод и ливай по return из них. Это если из трёх сразу. А если из двух? Вытаскивать эти два цикла в функцию не всегда целесообразно.  | 
    
| 
         
         
         
          
           Сообщ.
           #134
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата OpenGL @  Это если из трёх сразу. А если из двух? Вытаскивать эти два цикла в функцию не всегда целесообразно.  Заведи флаг выхода. В чем проблема? Цитата Славян @  Допустим так: Что тебе мешает эти два цикла обернуть в отдельную функцию?  | 
    
| 
         
         
         
          
           Сообщ.
           #135
          
          , 
          
         
         
        
       | 
    |
| 
         | 
      
         Цитата KILLER @  Мешает то, что эти два цикла и так по сути оформлены в функцию. Плюс вагон переменных, кои засылать в функцию равносильно заново написать примерно такую же. Что тебе мешает эти два цикла обернуть в отдельную функцию?     |