|
|
  |
Оператор GoTo, безусловный переход или правила хорошего тона |
|
|
|
Sep 29 2006, 15:13
|
Участник

Группа: Новичок
Сообщений: 20
Регистрация: 17-01-06
Пользователь №: 13 275

|
Почему считается, что "нехорошо" использовать данного оператора?
|
|
|
|
|
Sep 29 2006, 16:02
|
Частый гость
 
Группа: Свой
Сообщений: 185
Регистрация: 5-05-06
Из: Ekaterinburg, Russia
Пользователь №: 16 821

|
Как я понимаю, этот оператор неявно присутствует в основных конструкциях структурированных языков. Цикл то не организовать без goto  . Хотя, например, в C оператор goto присутствует, просто им не рекомендуют пользоваться. Вообщем, все вопросы приходят к разговору о стиле, используемом при разработке ПО (структурированное, объектно-ориентированное программирование и т.д.).
--------------------
Чудес не бывает - бывает мало знаний и опыта!
|
|
|
|
|
Sep 29 2006, 16:22
|
Участник

Группа: Новичок
Сообщений: 20
Регистрация: 17-01-06
Пользователь №: 13 275

|
Полностью согласен, взять ассемблер - циклов без меток и переходов не бывает. А ПОЧЕМУ в С не рекомендуют, или так сложилось, как байте восемь бит?
|
|
|
|
|
Sep 29 2006, 16:46
|
Участник

Группа: Участник
Сообщений: 27
Регистрация: 27-09-05
Пользователь №: 8 979

|
Это филосовский вопрос. И ответ на него будет: "В силу некоторых особенностей человеческого разума/мышления". Пока сами не почувствуете, объяснить более подробно будет сложно.
Сообщение отредактировал ktod - Sep 29 2006, 16:49
--------------------
Ignoramus et Ignorabimus
|
|
|
|
|
Sep 29 2006, 17:51
|
Участник

Группа: Новичок
Сообщений: 41
Регистрация: 20-08-06
Пользователь №: 19 688

|
go to не явно присутствует во всех языках всегда а идет это от гулявших ошибок перекрестных при применении нескольких go to на странице текста более чем 25 строк конструкция команда (условие){ что-то делать } логически читалась легче в 1980-ых написаны книги по стилю написания и оформления кода в 1988-мом Borland рекомендавал в TurboC2.0 постепенно переходить с goto на конструкции for, if и do ,а while еще не был придуман, try еще даже в мечтах не было Borland извинялся за неоптимальность компилируемого двоичного кода с конструкцией goto Вот с тех пор рекомендация на подсознательном уровне отложилась как правило для языков высокого уровня. Жестко вроде нигде не запрещенно Только рекомендации и извинения за возможные глюки а кому глюки нужны Тут бы быстрей как-то что-то Так что пиши как хочешь и где хочешь, а возможные глюки в самых древних из самых древних библиотек на твоей совести будут  пожелтевшие бумажные 700 листов Borland-овского Help-а еще где-то лежат но копаться и и цитировать лень могу только полку показать Im sorry
Сообщение отредактировал artem100 - Sep 29 2006, 18:02
Эскизы прикрепленных изображений
|
|
|
|
|
Sep 29 2006, 18:05
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата Почему считается, что "нехорошо" использовать данного оператора? Цитата из Бьерн Страуструп "Язык программирования С++" (типа один из разработчиков С++): 3.3.2 Оператор goto
Презираемый оператор goto все-таки есть в С++:
goto идентификатор;
идентификатор: оператор
Вообще говоря, он мало используется в языках высокого уровня, но может быть очень полезен, если текст на С++ создается не человеком, а автоматически, т.е. с помощью программы. Например, операторы goto используются при создании анализатора по заданной грамматике языка с помощью программных средств. Кроме того, операторы goto могут пригодиться в тех случаях, когда на первый план выходит скорость работы программы. Один из них - когда в реальном времени происходят какие-то вычисления во внутреннем цикле программы. Есть немногие ситуации и в обычных программах, когда применение goto оправдано. Одна из них - выход из вложенного цикла или переключателя. Дело в том, что оператор break во вложенных циклах или переключателях позволяет перейти только на один уровень выше.Цитата(bodja74 @ Sep 29 2006, 20:56)  Потому что оператор безусловного перехода не сохраняет адресс возврата в стеке,и если допустим функция в Си физически выступает как подпрограмма ,переходить к ней по безусловному переходу даже на асме крайне рискованое занятие ,так как в конце есть все шансы встретится с коммандой ret, которая загрузит из стека адресс возврата неизвестно какого значения и прога уйдет в ступор. Исчо критика  простите, если сможете В С/С++ goto не работает за пределами функции, так что проблем со стеком и с возвратом по ret никогда не может возникнуть, единственная проблемма возникающия со стеком при использовании goto заключается в следующем: Код for (i=0;i<10;i++) { char ar[1000]; if (i==5) goto label1; } label1: память занимаемая массивом ar[1000] будет возвращена системе только после выхода за следующий блок { ... } У Microsoft специально для этих целей вместо goto используется структурная обработка ошибок (не только для этих целей): __try { ...... if(...) __leave; ...... } __finally { ...... } которая корректно умеет обрабатывать стек. НО, если Вы поизучаете код который пишет Microsoft, то например в MFC Вы обнаружите более 70 файлов в которых используется оператор goto
|
|
|
|
|
Sep 29 2006, 18:39
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(J_B @ Sep 29 2006, 19:13)  Почему считается, что "нехорошо" использовать данного оператора? Да, забыл добавить: Лично я считаю применение goto крайним случаем. Иногда для скорости, а иногда чтобы не писать странные конструкции которые позволят избежать использования goto.
|
|
|
|
|
Sep 29 2006, 20:32
|
Знающий
   
Группа: Свой
Сообщений: 543
Регистрация: 22-10-05
Пользователь №: 9 984

|
Цитата(singlskv @ Sep 29 2006, 21:05)  [Исчо критика  простите, если сможете  Без проблем,у меня корона из головы не упадет.  Соглашусь со всем так как в Си не силен. Но позвольте высказать свое ИМХО.  Какие операторы не писали и какие бы скобки не ставили,в конечном итоге все сводится к трем елементарным инструкциям переходов - условный,безусловный и переход на подпрограмму (то есть опять же асм ,так как МК физически еще не научился понимать Си). Тоесть как будут откомпелированы команды на Си в элементарные команды и будут ли они допущены вообще - это зависит от интелекта компиллера Си ,а не от самого языка. Для ПК я пишу на VB6 ,там также с помощью GOTO из функции или подпрограммы не выпрыгнеш и не запрыгнеш ,так как метки для них локальны,но это не значит что на старом и добром TB под ДОС этого нельзя было делать. ЗЫ Если кому хочется побольше увидеть команд Jmp под Win (тот же GOTO) - дизасемблируйте прогу, их количество вас приятно удивит.  ЗЫЫ Раскажите чайнику для чего нужен MFC? Как то был интерес поизучать,зашел в книжный,как увидел габариты этого толмута,так сразу перехотелось,я на полном серьезе - этой книжицей с одного удара по голове можно убить человека. И перехотелось не потому ,что представил ,как буду долго и нудно ее изучать,а потому что представил,если разгорится спор,как моя жонка будет гонятся с этим толмутом за мной по квартире.
|
|
|
|
|
Sep 29 2006, 21:57
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(bodja74 @ Sep 29 2006, 23:32)  И перехотелось не потому ,что представил ,как буду долго и нудно ее изучать,а потому что представил,если разгорится спор,как моя жонка будет гонятся с этим толмутом за мной по квартире.  Фигня. Задача решаема. На вопрос "что бы подарить мне на день Варенья" жена получила ответ "Трехтомник Кнута". Ничего, сижу, читаю. Жив :-) В смысле - это жена у меня спрашивала насчет подарка.
Сообщение отредактировал Сергей Борщ - Sep 29 2006, 21:58
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 30 2006, 04:24
|
Участник

Группа: Новичок
Сообщений: 20
Регистрация: 17-01-06
Пользователь №: 13 275

|
Спасибо высказавшимся, просто написал переход от двоичной в двоично-десятичную (для семисегментников), и вспомнил про гоуту...
|
|
|
|
|
Sep 30 2006, 06:10
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(_artem_ @ Sep 30 2006, 01:40)  Была какая то статья, с которой весь этот садомазоэстетический спор в мире програмистов начался, не помню только ее название. Началась это на моей памяти Виртом с обоснования теоретической базы "Паскаля" как попытки создать язык идеальный для толкования компилятором ну априори предполагаемый "удобным" для пользователя ввиду его однозначности. Для компилятора, спору нет, goto в большинстве случаев - проблема, ибо начисто ломает его все стандартные "домашние заготовки". Соответственно простые компиляторы давних времен генерили весьма поганый код. Компиляторы поумнели и стали нормально понимать удобные человеку конструкции, идеалисты от компиляции продолжают движение и дошли до "Оберона". На сегодняшний день причин не использовать в "C" goto в удобном месте нет.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 30 2006, 09:43
|
Профессионал
    
Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886

|
Цитата(zltigo @ Sep 30 2006, 10:10)  На сегодняшний день причин не использовать в "C" goto в удобном месте нет. Хм.... Причина есть! И на сегодняшний день она ещё более актуальна! Дело в том, что сейчас серьёзный проект можно написать только работая в команде разработчиков. И для того, что бы в твоём коде можно было разобраться другому человеку, надо писать по общепринятым "правилам хорошего тона". Одним из правил является форматирование отступами вложенного кода (например тело цикла, условия - так проще найти глазами конец цикла и условия и т.д.). С использованием Goto такое форматирование осуществить в общем случае невозможно, что приводит полному мясу кода, который спустя некоторое время не только сторонний человек понять не сможет, но и даже сам разработчик. А компиляторы тут ни при чём, сейчас они умные. ИМХО любой логичный алгоритм можно изящно записать без Goto. Это как "любую мысль можно передать без мата".
|
|
|
|
|
Sep 30 2006, 10:04
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Petka @ Sep 30 2006, 12:43)  С использованием Goto такое форматирование осуществить в общем случае невозможно, что приводит полному мясу кода, который спустя некоторое время не только сторонний человек понять не сможет, но и даже сам разработчик. Если выражаться коротко, то это бред. Цитата ИМХО любой логичный алгоритм можно изящно записать без Goto. Это как "любую мысль можно передать без мата". Можно все, но не изящно. Ибо понятие изящно применимо к более-менее искуственно замкнутым системам. Там где на систему плотно влияют внешние непреодолимые обстоятельства там и требуются якобы "неизящные" выходы и не самые исключения, которые подтверждают правила. Причем попав в такую ситуацию я предпочитаю четко и ясно выразить свлю мысль, например словом "пи....ц", поятным каждому нормальному человеку а не "изящно" и муторно с жевать сопли для "литературной" передачи мысли.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 30 2006, 12:20
|
Частый гость
 
Группа: Новичок
Сообщений: 173
Регистрация: 3-09-04
Из: Moscow
Пользователь №: 595

|
Цитата(zltigo @ Sep 30 2006, 14:04)  Цитата(Petka @ Sep 30 2006, 12:43)  С использованием Goto такое форматирование осуществить в общем случае невозможно, что приводит полному мясу кода, который спустя некоторое время не только сторонний человек понять не сможет, но и даже сам разработчик.
Если выражаться коротко, то это бред. А если не коротко ? Пока не видно Ваших аргументов. Ждём примера кода, который без GOTO хуже, нежели с GOTO. imho, максимум, что может дать GOTO - это сократить код на 2-3 строки в ущерб читабельности программы. Цитата(zltigo @ Sep 30 2006, 14:04)  Цитата Это как "любую мысль можно передать без мата".
Причем попав в такую ситуацию я предпочитаю четко и ясно выразить свлю мысль, например словом "пи....ц" Не уподобляйтесь тем, у кого "косноязычие компенсируется скудоумием". Поверьте - русский язык велик и могуч. Хотя в Ваших краях, наверное, с его изучением туговато.
|
|
|
|
|
Sep 30 2006, 12:52
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(CD_Eater @ Sep 30 2006, 15:20)  А если не коротко ? А не коротко, по поводу отцитированного ничего и не скажешь :-(. Цитата Хотя в Ваших краях, наверное, с его изучением туговато. Тем не менее, я полагаю, что достаточно хорошо им (как в прочем и "C" ) владею и вполне внятно выразил причины использования и присутствия goto во всех реальных языках программирования не смотря на многодесятилетние теоретические размышления о "вреде", "возможности обойтись" и мифической "читабельности". Цитата Поверьте - русский язык велик и могуч. И делает его могучим именно присутствие элементов живого языка, таких как обсуждаемый здесь goto, и выгодно отличает его от "легко читаемых" с выброшенными "ненужностями" искусственных языков, типа Эсперанто.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 30 2006, 14:27
|
Участник

Группа: Новичок
Сообщений: 20
Регистрация: 17-01-06
Пользователь №: 13 275

|
Особо переделкой без goto не занимался, но кто что скажет: VAL=0; X=100; foR(I=0;I<=2;I++) { LABEL: TMP_P=TMP; TMP=TMP-X; if(TMP<0) { SEG[i]=VAL; VAL=0; TMP=TMP_P; X=X/10; } else { VAL=VAL++; goto LABEL; }
}
Смысл таков: есть заранее неизвестное значение (16р) в диапазоне 0-999 - TMP. Вывод на тройной индикатор SEG0-2. Идея:" Способ преобразования заключается в том, чтобы, вычитая из исходного числа число 100, сначала определить десятичную цифру десятков сотен. Затем находится цифра десятков последовательным вычитанием числа 10 и т. д. Вычитание каждый раз производится до получения отрицательной разности с подсчетом числа вычитаний. При переходе к определению каждого следующего десятичного разряда в регистрах исходного числа восстанавливается последняя положительная разность"
|
|
|
|
|
Sep 30 2006, 14:40
|
Профессионал
    
Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886

|
Цитата(zltigo @ Sep 30 2006, 14:04)  Цитата(Petka @ Sep 30 2006, 12:43)  С использованием Goto такое форматирование осуществить в общем случае невозможно, что приводит полному мясу кода, который спустя некоторое время не только сторонний человек понять не сможет, но и даже сам разработчик.
Если выражаться коротко, то это бред. Аргументы? В электронику я перешёл из "программистов". Могу позволить себе утверждать, что Вы не до конца освоили работу в команде, как и отличие языков высокого уровня от низкого. Недавно в форуме пробегала ссылка на "косметику для программистов". Советую ознакомится.
|
|
|
|
|
Sep 30 2006, 14:56
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(J_B @ Sep 30 2006, 17:27)  Смысл таков: Если не касаться прочих многочисленных, назовем - странностей, то просто вообще уберите две строки label: и goto label; и добавьте цикл с break; Если зачем-то кто-то пишет такое, то я начинаю понимать Petka :-)
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 30 2006, 15:07
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Petka @ Sep 30 2006, 17:40)  Аргументы? Попробуйте преречитать написанное Вами: Цитата Одним из правил является форматирование отступами вложенного кода (например тело цикла, условия - так проще найти глазами конец цикла и условия и т.д.). С использованием Goto такое форматирование осуществить в общем случае невозможно.... Я искренне не понимаю какие аргументы от меня требуются :-((((
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Sep 30 2006, 15:45
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(J_B @ Sep 30 2006, 18:27)  Особо переделкой без goto не занимался, но кто что скажет: Код VAL=0; X=100; for(I=0;I<=2;I++) { LABEL: TMP_P=TMP; TMP=TMP-X; if(TMP<0) { SEG[i]=VAL; VAL=0; TMP=TMP_P; X=X/10; } else { VAL=VAL++; goto LABEL; } } Смысл таков: есть заранее неизвестное значение (16р) в диапазоне 0-999 - TMP. Вывод на тройной индикатор SEG0-2. Идея:" Способ преобразования заключается в том, чтобы, вычитая из исходного числа число 100, сначала определить десятичную цифру десятков сотен. Затем находится цифра десятков последовательным вычитанием числа 10 и т. д. Вычитание каждый раз производится до получения отрицательной разности с подсчетом числа вычитаний. При переходе к определению каждого следующего десятичного разряда в регистрах исходного числа восстанавливается последняя положительная разность" Скажу только, что Код goto LABEL; здесь абсолютно бессмысленен, т.к. точно такой же по смыслу переход уже присутствует в силу организации цикла. По сути программы: если Вы хотели уйти от деления, Вам это таки не удалось. Сделайте хотя бы так: Код if(TMP<0) { SEG[i]=VAL; VAL=0; TMP=TMP_P; if(X==100) X=10; else if(X==10) X=1; else break; } А еще проще посмотреть сорцы для BCD преобразования. Бр-р-р. Не посмотрел на уловия цикла. Здесь и goto не поможет  .
|
|
|
|
|
Sep 30 2006, 16:02
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(zltigo @ Sep 30 2006, 19:55)  Код seg[0] = tmp/100; seg[2] = tmp%10; tmp /= 10; seg[1] = tmp%10; Ну так не интересно  . Без выподвывертов-то  .
|
|
|
|
|
Sep 30 2006, 21:25
|

Знающий
   
Группа: Свой
Сообщений: 902
Регистрация: 2-01-06
Из: Краснодар
Пользователь №: 12 768

|
for(I=0;I<=2;I++) { do{ TMP_P=TMP; TMP=TMP-X; if(TMP>=0) ++VAL; } while(TMP>=0) SEG[i]=VAL; VAL=0; TMP=TMP_P; X=X/10; } _artem_Извиняюсь,погорячился,тоже кривовато получается,но все-таки можно и без GOTO  Еще раз извиняюсь,прочел предыдущую страницу,это все вообще не из той оперы.
--------------------
"Hello, word!" - 17 errors 56 warnings
|
|
|
|
|
Oct 1 2006, 15:39
|

учащийся
    
Группа: Свой
Сообщений: 1 065
Регистрация: 29-10-05
Из: города контрастов
Пользователь №: 10 249

|
Вы правы - http://en.wikipedia.org/wiki/GOTOНо что интересно: "there are some tasks that cannot be straightforwardly accomplished in many programming languages without the use of GOTO statements, such as breaking out of nested loops and exception handling." и имхо это действительно так.
--------------------
Зачем лаять на караван , когда на него можно плюнуть?
|
|
|
|
|
Oct 2 2006, 07:48
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(J_B @ Sep 29 2006, 18:13)  Почему считается, что "нехорошо" использовать данного оператора? Дурным тоном в программировании является не само использование оператора goto, а его частое и неоправданное использование. В таких случаях программа получается запутанной и трудной для понимания, а, стало быть, для отладки или соправождения. Современные языки программирования (Си в том числе) имеют управляющие конструкции, позволяющие в принципе обходится без goto. Однако в ряде случаев использование goto позволяет сделать программу более понятной. Речь идет о тех случаях, когда необходимо сделать выход из вложенных циклов. В таких случаях оператор goto позволяет исключить введение множества флагов, используемых для проверки условия принудительного выхода из циклов. При этом программа получается не только более наглядной, но и более эффективной. Основное правило использования goto - переход только вперед. Если goto используется для перехода назад, то это означает, что необходимо воспользоваться каким-либо оператором цикла и/или оператором принудительного перехода к очередной итерации цикла - continue. А вообще, непонятную и нечитаемую программу можно легко написать и не используя оператор goto. Это часто происходит потому, что человек еще не совсем представляет что именно ему нужно. Поэтому, прежде чем писать код, лучше сначала продумать структуру программы. Методы структурного программирования известны не один десяток лет. В современных языках программирования имеются все необходимые конструкции для создания структурированных программ: последовательно исполняемые операторы (простые и составные), операторы ветвления (if, if...else, switch (case), goto), цикла (while, do...while, for). Мои размышления о "косметики" программ можно найти здесь.
|
|
|
|
|
Oct 2 2006, 08:22
|
Участник

Группа: Участник
Сообщений: 34
Регистрация: 28-09-06
Из: Минск
Пользователь №: 20 776

|
Что касается AVR и goto, то при использовании оптимизации кода по размеру, этот оператор опасно использовать. При использавании Cross Call могут действительно возникнуть проблемы со стеком. Так что лучше не рисковать! Можно просто поэкпериментировать, компилируя программу с разными настройками оптимизации - хороший код должен работать в любом случае.
|
|
|
|
|
Oct 2 2006, 08:35
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(AVNN @ Oct 2 2006, 11:22)  Что касается AVR и goto, то при использовании оптимизации кода по размеру, этот оператор опасно использовать. При использавании Cross Call могут действительно возникнуть проблемы со стеком. Так что лучше не рисковать! Можно просто поэкпериментировать, компилируя программу с разными настройками оптимизации - хороший код должен работать в любом случае. А какие тут могут бть проблемы?
|
|
|
|
|
Oct 24 2007, 06:19
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 15-03-07
Пользователь №: 26 183

|
Во всех наставлениях по СИ для МК "...настоятельно не рекомендуется использовать оператор безусловного перехода goto, т.к. он затрудняет понимание программ и возможность их модификаций...". В то же время другими операторами СИ не всегда удобно осуществлять переходы, а в ассемблере применение команд jmp и rjmp ограничений почти нет. Для примера в программе "кодовый замок" из книги Белова А.В., в небольшом тексте программы на CИ в модуле main 7 переходов. И все работает нормально. Может быть, кто то потвердит вводное утверждение и покажет как надо на приложенном тексте.
Прикрепленные файлы
Zamok.txt ( 4.23 килобайт )
Кол-во скачиваний: 84
|
|
|
|
|
Oct 24 2007, 06:45
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Чисто в лоб типа такого Код while (1) {
do {
while (incod() != klfree); // Ожидание отпускания кнопок while (incod() == klfree); // Ожидание нажатия кнопок ii=0; do { #asm("cli"); // Запрещаем прерывания wait(1); // Задержка 1-го типа codS=incod(); // Ввод кода и запись, как старого bufr[ii++]=codS; // Запись очередного кода в буфер if (ii>=bsize) break; // Проверка конца буфера wait(2); // Задержка 2-го типа do { if (incod() != codS) break; // Проверка не изменилось ли состояние
} while((flz==0)); // Проверка окончания контрольного промежутка времени } while(1);
if (PINB.7==1) { if (klen!=ii) continue; // Проверка длины кода } //------------------------------ Запись кода в EEPROM klen=ii; // Запись длины кода for (i=0; i<ii; i++) bufe[i]=bufr[i]; // Запись всех байтов кода break;
//------------------------------ Проверка кода if (klen!=ii) continue; // Проверка длины кода for (i=0; i<ii; i++) if (bufe[i]!=bufr[i]) continue; // Проверка самого кода break; //------------------------------ Открывание замка } while(1); PORTB.4=1; // Открываем замок wait(3); // Задержка 3-го типа PORTB.4=0; // Закрываем замок }; Может есть ошибки, да и упростить можно, но суть та же goto нафик не нужен При чем тут AVR кстати ? Цитата(ValBag @ Oct 24 2007, 10:19)  В то же время другими операторами СИ не всегда удобно осуществлять переходы Кто такое сказал, автор или Вы? goto реально упрощает обработку чего-то экстраординарного, но для этого лучше применть блоки try catch в С++
|
|
|
|
|
Oct 24 2007, 07:07
|
Местный
  
Группа: Свой
Сообщений: 263
Регистрация: 22-03-05
Из: г. Харьков, Украина
Пользователь №: 3 598

|
Ну результат почти такой же. В текущем примере из-за goto тяжело понять логику, поэтому пришлось импровизировать. Пример можно еще оптимизировать. А вообще-то стиль написания напомнил asm. Видимо человек до этого долго писал на нем, отсюда логика построения функции. А в бейсике без него сильно не поработаешь :-)
|
|
|
|
|
Oct 24 2007, 07:19
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(ValBag @ Oct 24 2007, 13:19)  Во всех наставлениях по СИ для МК "...настоятельно не рекомендуется использовать оператор безусловного перехода goto, т.к. он затрудняет понимание программ и возможность их модификаций...". В то же время другими операторами СИ не всегда удобно осуществлять переходы, а в ассемблере применение команд jmp и rjmp ограничений почти нет. Существует очень мало ситуаций, где этот оператор действительно необходим. В ~90% случаев это выход из вложенных циклов. Собсно, для этого оператор и оставили в языке. При всяком его применении нужно минимум дважды задуматься, действительно ли он тут необходим или задача может быть решена другими средствами. И уж злоупотребление (т.е. применение где ни попадя) им во всяком случае должно быть предотвращено. P.S. Вообще-то, это вопрос для FAQ, его постоянно задают начинающие.  И частенко обсуждения достоинств и недостатков этого оператора приводят к "религиозным" войнам, по какой причине в некоторых местах (например, в фидо-эхе su.c-cpp) обсуждение оператора goto объявлено офтопиком и преследуется модератором по закону.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Oct 24 2007, 07:23
|
Местный
  
Группа: Участник
Сообщений: 406
Регистрация: 1-03-06
Пользователь №: 14 821

|
Цитата(ValBag @ Oct 24 2007, 08:19)  Для примера в программе "кодовый замок" из книги Белова А.В., в небольшом тексте программы на CИ в модуле main 7 переходов. И все работает нормально. Может быть, кто то потвердит вводное утверждение и покажет как надо на приложенном тексте. Работать goto будет всегда, если правильно запрограммировал! Просто суть в том, что человеку будет труднее понять вашу функцию с 7  goto, хотя и спорно. Мне, например труднее понять с do while. Вообщее это дело вкуса.
|
|
|
|
|
Oct 24 2007, 10:02
|
Участник

Группа: Validating
Сообщений: 56
Регистрация: 15-10-06
Пользователь №: 21 335

|
А собственно чего все так на бедного goto оплчились ? IMHO Даден инструмент в языке - надо - пользуйся , только думай что делаешь  Молотком тоже можно самого себя прибить  но их-же никто не запрещает... А ведь были еще setjmp/longjmp  про них вообще можно много интересного рассказать  и тож goto в каком-то смысле
Сообщение отредактировал Maddy - Oct 24 2007, 10:02
|
|
|
|
|
Oct 24 2007, 11:46
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(IEC @ Oct 24 2007, 09:07)  А вообще-то стиль написания напомнил asm. Там комментарий есть такой вот This program was produced by the CodeWizardAVR V1.24.4 Standard Automatic Program GeneratorНе знаю - что за генератор и из чего он генерировал, но на "трансляцию" блок-схемы с ромбиками проверки условий очень похоже. А транслятору блок-схем в С как промежуточный язык можно и разрешить ставить goto в немеряных количествах - пока получившийся текст не предназначен для чтения человеком и пока "сопровождается" блок-схема, а не сгенерированный из неё С-код. Честно говоря, программа и организована как-то странно, "первым проходом" я её переписал бы так: CODE #define F_CPU 4000000UL #include <tiny2313.h>
#define SYSTICK_MS 25 // приблизительно 24 мс период прерываний // прескалер для таймера 1 1/64 #define SYSTICK_DELTA ((F_CPU / 64 * SYSTICK_MS + 500) / 1000) // смещение OCR // времена в милисекундах, максимум SYSTICK_MS * 255 #define KEY_TIMEOUT (1000 / SYSTICK_MS) #define LOCK_DELAY (3000 / SYSTICK_MS) #define KEY_MASK 0x77F // маска используемых клавиатурой битов #define BSIZE 30 // Размер буфера для хранения кода
unsigned int bufr[BSIZE]; // Буфер в ОЗУ для хранения кода #pragma warn- eeprom unsigned char klen; // Ячейка для хранения длины кода eeprom unsigned int bufe[BSIZE]; // Буфер в EEPROM для хранения кода #pragma warn+
volatile unsigned char timeout; volatile unsigned key_filtered = 0; volatile unsigned char key_changed = 0;
// Прерывание по совпадению в канале A Таймера 1 interrupt [TIM1_COMPA] void timer1_compa_isr(void) { static unsigned prev; unsigned current; OCR1A += SYSTICK_DELTA; if( timeout) --timeout; // мне больше нравится, когда нажатая кнопка даёт единичку, ничего не нажато - нули // поэтому инвертируем состояние PIN current = KEY_MASK & ~((PINB << 8) | PIND); if( current == prev ) { // не дребезжит if( key_filtered != current) { // и поменялось key_changed = 1; key_filtered = current; } } prev = current; }
unsigned int get_key(void) { unsigned key = 0; if( key_changed) { #asm ("cli"); key = key_filtered; key_changed = 0; #asm ("sei"); } return key; }
// Основная функция void main(void) { unsigned char key_index; // Указатель массива unsigned char i; // Вспомогательный указатель unsigned int key;
PORTB = 0xE7; // Порт B DDRB = 0x18;
PORTD = 0x7F; // Порт D DDRD = 0x00;
TCCR1A = 0x00; // Таймер/Счетчик 1 TCCR1B = 0x03; TCNT1 = 0; OCR1A = SYSTICK_DELTA;
ACSR = 0x80; // Аналоговый компаратор #asm ("sei"); while (1) { // Главный цикл key_index = 0; // Пока буфер пуст либо начали набирать, но не кончился таймаут - ждём нажатий while( key_index == 0 || timeout != 0 ) { key = get_key(); if( key ) { bufr[key_index] = key; timeout = KEY_TIMEOUT; if( ++key_index >= BSIZE) break; } }
// полный буфер или пауза между клавишами > KEY_TIMEOUT, реакция на набранный код if (PINB.7 == 1) { // Проверка переключателя режимов //------------------------------ Проверка кода if ( key_index != klen ) // Проверка длины кода continue; for (i = 0; i < key_index; i++) if (bufe[i] != bufr[i]) // Проверка самого кода continue; } else { //------------------------------ Запись кода в EEPROM klen = key_index; // Запись длины кода for (i = 0; i < key_index; i++) bufe[i] = bufr[i]; // Запись всех байтов кода }
//------------------------------ Открывание замка // оставлено как было - замок открывается и после ввода нового кода, возможно, // это было задумано как подтверждение замены. PORTB.4 = 1; // Открываем замок timeout = LOCK_DELAY; while( timeout) ; PORTB .4 = 0; // Закрываем замок } }
Количество строк С-программы ~ не изменилось, объём кода, думаю, не сильно изментися, но теперь можно независимо задавать время таймаута нажатия клавиш и время удержания замка открытым. А вообще и проверку кода, и запись нового - я бы выделил в static inline функции (просто static для компилятора, до сих пор не поддерживающего С99) - вменяемый оптимизатор даже просто static функцию проинлайнил бы по месту и объём кода не изменился бы, а "читабельность" выросла бы. Да и часть комментариев ушла бы за ненадобностью, так как Код else write_new_code_to_eeprom() столь же понятно, как и Код else { //------------------------------ Запись кода в EEPROM
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 24 2007, 11:55
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(dxp @ Oct 24 2007, 09:19)  Существует очень мало ситуаций, где этот оператор действительно необходим. В ~90% случаев это выход из вложенных циклов. Ещё в 9% случаев - слияния разных ветвей case в общие: после некоторых разных предварительных операций в относительно длинную общую часть - тогда для сопровождения проще не дублировать эту общую часть (а потом забыть одну из них модифицировать), а поставить несколько goto. Но это для "избранных" мест, старательно вылизываемого "где-то-библиотечного" кода. Иногда - сведение ветвей многоступенчатых if, но это почти то же самое. А вот в приведенной программе goto явно от неумения писать на С, а не от большого умения :-) Цитата(DASM @ Oct 24 2007, 13:49)  OFF - ReAL - а как код в трубочку свернули ? Тег CODEBOX вместо CODE
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 24 2007, 12:06
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 15-03-07
Пользователь №: 26 183

|
Перечитал всю тему. На мой взгляд отказ от применения GoTo это стародавняя аксиома, которая в большинстве случаев многими принимается на веру. Тот же Страуструп (из топика #11) пишет: Цитата Кроме того, операторы goto могут пригодиться в тех случаях, когда на первый план выходит скорость работы программы. Один из них - когда в реальном времени происходят какие-то вычисления во внутреннем цикле программы. Есть немногие ситуации и в обычных программах, когда применение goto оправдано. Одна из них - выход из вложенного цикла или переключателя. Дело в том, что оператор break во вложенных циклах или переключателях позволяет перейти только на один уровень выше. Не считайте меня назойливым, еще раз обращаюсь к корифеям. Отредактируйте, пожалуйста текст программы (из топика #44) с пресловутым GoTo, чтобы она работала с другими операторами. Хочу увидеть разницу и приобрести некоторый опыт на живом примере. Ответы "сделай сам" не хотелось бы принимать. Все учились на чужих и своих примерах. Спасибо!
|
|
|
|
|
Oct 24 2007, 12:27
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ValBag @ Oct 24 2007, 14:06)  Отредактируйте, пожалуйста текст программы (из топика #44) с пресловутым GoTo, чтобы она работала с другими операторами. А чем не нравится мой вариант? Нужны шашечки или ехать? Я переписал не изменив "внешнюю" логику программы, но без goto, кто сказал, что оно должно выглядеть очень похоже на старое? Дословный перевод с языка на язык может либо исказить мысль больше, чем "правильный" перевод, либо выглядеть коряво. А тут мы переводим текст с чего-то типа бейсик-программы, записанной словами С на собственно С  Тем более, что изменён только набор кода с клавиатуры, оставлено даже его поведение таким, как было, просто антидребезг и проверка нажатия новой клавиши реализованы несколько по-другому - гибче и расширяемее. Заодно убрана эту ужасающая задержка через wait() с "магическими числами". Всё остальное просто переписано без goto. Ну вот "тупо" переведённый из goto-шного варианта в не-goto-шный: CODE /***************************************************** This program was produced by the CodeWizardAVR V1.24.4 Standard Automatic Program Generator © Copyright 1998-2004 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.come-mail:office@hpinfotech.com Project : Пример 10 Version : 1 Date : 07.03.2006 Author : Belov Company : Home Comments: Кодовый замок Chip type : ATtiny2313 Clock frequency : 4,000000 MHz Memory model : Tiny External SRAM size : 0 Data Stack size : 32 *****************************************************/ #include <tiny2313.h> #define klfree 0x77F // Код состояния при полностью отпущеных кнопках #define kzad 3000 // Код задержки при сканировании #define kandr 30 // Константа антидребезга #define bsize 30 // Размер буфера для хранения кода unsigned char flz; // Флаг задержки unsigned int bufr[bsize]; // Буфер в ОЗУ для хранения кода #pragma warn- eeprom unsigned char klen; // Ячейка для хранения длины кода eeprom unsigned int bufe[bsize]; // Буфер в EEPROM для хранения кода #pragma warn+ // Прерывание по переполнению Таймера 1 interrupt[TIM1_OVF] void timer1_ovf_isr(void) { flz = 1; // Устанавливаем флаг задержки } // Прерывание по совпадению в канале A Таймера 1 interrupt[TIM1_COMPA] void timer1_compa_isr(void) { flz = 1; // Устанавливаем флаг задержки } // Функция опроса клавиатуры и антидребезга unsigned int incod(void) { unsigned int cod0 = 0; // Локальные переменные unsigned int cod1; unsigned char k; for (k = 0; k < kandr; k++) { // Цикл антидребезга cod1 = PINB & 0x7; // Формируем первый байт кода cod1 = (cod1 << 8) + (PIND & 0x7F); // Формируем полный код состояния клавиатуры if (cod0 != cod1) { // Сравниваем со старым кодом k = 0; // Если не равны, сбрасываем счетчик cod0 = cod1; // И присваиваем новое значение старому коду } } return cod1; } // Процедура формирования задержки void wait(unsigned char kodz) { if (kodz == 1) TIMSK = 0x40; // Выбор маски прерываний по таймеру else TIMSK = 0x80; TCNT1 = 0; // Обнуление таймера flz = 0; // Сброс флага задержки #asm("sei"); // Разрешаем прерывания if (kodz != 2) while (flz == 0); // Цикл задержки } // Основная функция void main(void) { unsigned char ii; // Указатель массива unsigned char i; // Вспомогательный указатель unsigned int codS; // Старый код PORTB = 0xE7; // Порт B DDRB = 0x18; PORTD = 0x7F; // Порт D DDRD = 0x00; TCCR1A = 0x00; // Таймер/Счетчик 1 TCCR1B = 0x03; TCNT1 = 0; OCR1A = kzad; ACSR = 0x80; // Аналоговый компаратор while (1) { // Главный цикл while (incod() != klfree); // Ожидание отпускания кнопок while (incod() == klfree); // Ожидание нажатия кнопок ii = 0; // набор кода до конца буфера либо до таймаута между клавишами while(1) { #asm("cli"); // Запрещаем прерывания wait(1); // Задержка 1-го типа codS = incod(); // Ввод кода и запись, как старого bufr[ii++] = codS; // Запись очередного кода в буфер if (ii >= bsize) // Проверка конца буфера break; wait(2); // Задержка 2-го типа while( flz == 0) { // пока не закончился интервал if (incod() != codS) // Проверка не изменилось ли состояние continue; // переход на набор кода } break; // таймаут - конец набора } // реакция на набранный код if (PINB.7 == 1) { // Проверка переключателя режимов //------------------------------ Проверка кода if (klen != ii) // Проверка длины кода continue; // главный цикл for (i = 0; i < ii; i++) if (bufe[i] != bufr[i]) // Проверка самого кода continue; // главный цикл } else { //------------------------------ Запись кода в EEPROM klen = ii; // Запись длины кода for (i = 0; i < ii; i++) bufe[i] = bufr[i]; // Запись всех байтов кода } //------------------------------ Открывание замка PORTB .4 = 1; // Открываем замок wait(3); // Задержка 3-го типа PORTB .4 = 0; // Закрываем замок } } p.s. сам я к этому вопросу не отношусь "религиозно" - goto применяю, но только если он действительно улучшает ситуацию.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 24 2007, 12:29
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 15-03-07
Пользователь №: 26 183

|
Цитата(DASM @ Oct 24 2007, 20:09)  А что по вашему ReAl сделал ? Прошу прощения, я его увидел после посылки своего предыдущего сообщения. Проработаю. Спасибо ReAl-у
|
|
|
|
|
Oct 24 2007, 12:50
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Раз уж я тут застрял - что я имел ввиду под "ужасающим wait()" Функция должна делать более-менее однотипную работу. Поэтому передавать в функцию параметр, меняющий время задержки - это нормально, но нагружать эту же функцию только инициализацией таймаута, который будет проверяться в другом месте и другим образом - это сделать код плохо читаемым (то же относится к макросам в ассемблере). На скорую руку предлагаемые изменения выглядят так: CODE typedef enum { delay_50ms, delay_1s } delay_code_t; // Процедура формирования задержки void init_timer(delay_code_t dly ) { if (dly == delay_50ms) TIMSK = (1 << OCIE1A); // Выбор маски прерываний по таймеру else TIMSK = (1 << TOIE1); TCNT1 = 0; // Обнуление таймера flz = 0; // Сброс флага задержки #asm("sei"); // Разрешаем прерывания }
#define init_timeout() init_timer(delay_1s) #define is_expired() (flz==1)
void wait(delay_code_t dly ) { init_timer( dly); while ( ! is_expired() ); // Цикл задержки }
// Основная функция void main(void) { ........
while (1) { // Главный цикл ......... // набор кода до конца буфера либо до таймаута между клавишами while(1) { #asm("cli"); // Запрещаем прерывания wait(delay_50ms); // Задержка 1-го типа codS = incod(); // Ввод кода и запись, как старого bufr[ii++] = codS; // Запись очередного кода в буфер if (ii >= bsize) // Проверка конца буфера break;
init_timeout(); // Задержка 2-го типа while( ! is_expired() ) { // пока не закончился интервал if (incod() != codS) // Проверка не изменилось ли состояние continue; // переход на набор кода } break; // таймаут - конец набора } ............. //------------------------------ Открывание замка PORTB .4 = 1; // Открываем замок wait(delay_1s); // Задержка 3-го типа PORTB .4 = 0; // Закрываем замок } }
Прошу прощения, на ходу кое-что поменял в уже отправленном коде. Цитата(defunct @ Oct 24 2007, 14:42)  Программа содержит аж 2 артефакта, первый конечно же goto, а второй - переменная "ii", давненько уже такого не видал  Ото ж я быстренько-быстренько оставил только i как "временный" счётчик цикла, а вторую переименовал в осмысленный key_index, чтобы в глазах от i ii iii не рябило
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 24 2007, 13:09
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 15-03-07
Пользователь №: 26 183

|
ReAl Цитата А тут мы переводим текст с чего-то типа бейсик-программы, записанной словами С на собственно С Неужели я применяю такой древний компилятор (такой же как в приложенном примере, кстати не моем, а указанного автора) который никто не знает. CodeVisionAVR это компилятор языка С http://www.hpinfotech.com У меня нет конкретного учителя. Подходящий для начинающих (по информации в литературе для новичков и ссылкам в сети) это CVAVR. Большинство утверждают, что самый лучший IAR, но по нему информации пользователя на русском нет, а уменя проблемы с английским. Вот такие дела! Спасибо за варианты, проработаю позже. С лету, как начинающий, не могу сразу оценить. defunct А чему противоречит название переменной ii?
|
|
|
|
|
Oct 24 2007, 13:16
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(ValBag @ Oct 24 2007, 16:09)  А чему противоречит название переменной ii? Лишь только читаемости кода, которая приводит в последствии к страшным глюкам сравните: Код ii += 1; ... for(i = 0; i < ii; i++) Код i += 1; ... for(i = 0; ii < ii; i++) Код ii += 1; ... for(i = 0; i < ii; ii++)
|
|
|
|
|
Oct 24 2007, 13:46
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ValBag @ Oct 24 2007, 15:09)  ReAl Неужели я применяю такой древний компилятор (такой же как в приложенном примере, кстати не моем, а указанного автора) который никто не знает. Нет, при чём тут "древний"? http://www.lib.ru/ANEKDOTY/non_pas.txtЦитата - поскольку в Фортране отсутствуют структурные операторы IF, REPEAT ... UNTIL или CASE, настоящим программистам не нужно беспокоиться, что они их не используют; кроме того эти операторы можно при необходимости симулировать с помощью присваиваемых GOTO. ... Да и потом, закоренелый настоящий программист может написать фортрановскую программу на любом языке. Именно это я имел ввиду - пример от "указанного автора" написан, как я сказал, "словами С но на другом языке". Довольно, на мой взгляд, грязный код, там кроме goto и ii есть что поругать (два прерывания там, где можно было обойтись одним - даже если писать не так, как написал я), лишние (с непонятной смысловой нагрузкой) вызовы inkey(), использование "магических чисел" там, где для упрощения понимания написанного и будущего развития надо применять именованные вещи, будь-то #define или enum. К "свежести" используемого Вами С-компилятора это не имеет никакого отношения, я лично никого не "пристыдил" - я вообще только понаслышке знаю - кто такие ImageCraft-ы с CodeVision-ами, мне и gcc хватает
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 24 2007, 14:01
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 15-03-07
Пользователь №: 26 183

|
Цитата(ReAl @ Oct 24 2007, 21:46)  пример от "указанного автора" написан, как я сказал, "словами С но на другом языке". "Указанный автор" это Белов А.В. Книга называется "Создаем устройства на микроконтроллерах". Это единственная книга, которую я нашел, с законченными примерами. Причем все примеры вначале приведены на ассемблере, а затем на С. Наверное этим и объясняется GoTO. Несмотря на это, кое что полезное я из нее извлек.
|
|
|
|
|
Oct 25 2007, 12:45
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 15-03-07
Пользователь №: 26 183

|
REAL Шашечек конечно не надо, но и ехать не получается. Глохнем на полпути. Это я так, беззлобно, скорее в отношении себя.
1. Общие принципы избавления от GoTo мне понятны, но не до конца. Самое проблемное место, переход из вложенных циклов вверх, более чем на начало вложенного цикла. Во втором и третьем Ваших вариантах первый оператор continue должен передаваь управление (по условию его действия) не на набор кода while(1), а на следующий цикл вложенного while(flz==0), в теле которого он появился? Буду рад, если ошибаюсь. В первом варианте программы, еще не разобрался, комментарии Ваши не везде, а до Вашего мастерства мне далековато.
2. typedef enum {delay_50ms, delay_1s} delay_code. А typedef здесь зачем?, delay_code это переменная объявленного перечисления с уже заданным типом.
Сообщение отредактировал ValBag - Oct 25 2007, 12:47
|
|
|
|
|
Oct 25 2007, 22:04
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ValBag @ Oct 25 2007, 14:45)  Самое проблемное место, переход из вложенных циклов вверх, более чем на начало вложенного цикла. Во втором и третьем Ваших вариантах первый оператор continue должен передаваь управление (по условию его действия) не на набор кода while(1), а на следующий цикл вложенного while(flz==0), в теле которого он появился? Тьху, это я ошибся. Конечно, оно идёт не туда, куда надо :-( Ну плохо "втупую" переводится "спагетти" из goto в циклы. В первом варианте, когда я "понял, что нужно и написал почти с нуля", надеюсь, ошибок нет :-) А тут надо что-то в таком духе рожать: Код init_timeout(); // Задержка 2-го типа while( incod() == codS && !is_expired() ); // пока клавиша не изменилась и таймаут не истёк - ждём if( is_expired() ) break; // если таки таймаут - конец набора } // это от while(1) "набор кода" Цитата(ValBag @ Oct 25 2007, 14:45)  2. typedef enum {delay_50ms, delay_1s} delay_code. А typedef здесь зачем?, delay_code это переменная объявленного перечисления с уже заданным типом. Нет, если бы не было слова typedef, то это была бы переменная типа неименованного enum с таким-то набором. А так это перечислимый тип - определяется typedef-ом для того, чтобы не писать лишний раз слово enum везде, где нужно завести переменную этого типа. Вместо Код enum moo { moo0, moo1 }; // только объявляем тип, не заводя переменных void foo( enum moo m) // аргумент этого типа { if( m == moo1) { ... пишем Код typedef enum { moo0, moo1 } moo_t; // тоже объявляем тип, но имя типа теперь из одного слова, без ключевого слова enum void foo( moo_t m) // аргумент этого типа { if( m == moo1) { ...
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 27 2007, 10:16
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ValBag @ Oct 27 2007, 10:58)  Только наверное надо немного изменить этот оператор? while ((incod() == codS) && (!is_expired())); Тут эти скобки не обязательны - согласно приоритету операций. А лишние скобки только мешают читать, особенно тут возле !is_expired() Никто же не пишет ((a*b)+(c*d))p.s. Да, это надо привыкнуть, что && и || имеют более низкий приоритет, чем == != > и т.д., а + - * / имеют более высокий, чем == != и т.д. Но ведь в школе же привыкли к приоритетам арифметических операций :-) Тем более, что логика в этих приоритетах есть, если словами сказать "если код не равен старому И не закончилось время" - это ведь в русском языке означаент не "если код не равен (старому и не закончилось)", а таки "(если не равен старому) и (не закончилось)" Единственное, пожалуй, неудобное место по приоритетам операций в С - это соотношение сложения и сдвига a << 5 + 1 означает a << (5 + 1) а не (a << 5) + 1 По крайней мере мне кажется более естественным размещение приоритета сдвигов между умножением-делением и сложением-вычитанием, а не ниже сложения-вычитания, но K&R решили по-другому и сдвиг надо брать в скобки.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 28 2007, 11:32
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(ReAl @ Oct 24 2007, 14:55)  Ещё в 9% случаев - слияния разных ветвей case в общие: после некоторых разных предварительных операций в относительно длинную общую часть - тогда для сопровождения проще не дублировать эту общую часть (а потом забыть одну из них модифицировать), а поставить несколько goto. Но это для "избранных" мест, старательно вылизываемого "где-то-библиотечного" кода. Иногда - сведение ветвей многоступенчатых if, но это почти то же самое. Мне как-то редко приходится использовать много вложенных циклов и я не объединяю (посредством GOTO) case-ы (сам IAR достаточно хорошо их объединяет). В то же время изредка пользуюсь GOTO по причине которая уже указывалась. Обработка исключительных ситуаций. Причём в Pascal это используется чаще так как в Си можно сделать дополнительный return. Хотя этим нарушается ещё одно "золотое правило": Для каждой процедуры - один вход - один выход. Конечно прямая обработка исключений - красивый выход как в С++ так и в Pascal, но иногда банально не хочется городить огород. К тому же я тоже считаю что основная причина - хорошая читаемость текста. С этой точки зрения вот такой текст к примеру - вполне укладывается Код procedure TForm1.mnuWriteClick(Sender: TObject); label ExitSend; const SmallTime = 20; BigTime = 400; var .... if CountRep>3 then begin StatusBar1.Panels.Items[0].Text:= 'Ошибка! Кластер с запрошенным номером не отвечает'; goto ExitSend; end; ..... if CountRep>3 then begin StatusBar1.Panels.Items[0].Text:= 'Ошибка! Превышено количество повторов во время передачи'; goto ExitSend; end; .... ExitSend: FComDriver.Active := false; FComDriver.Free; FComSettings.Free; StatusBar1.Panels.Items[0].Text:= ''; Form1.StatusBar1.Panels.Items[1].Text:= ''; end .... Сори - на Си не нашёл. Понятно что всё это можно флагами сделать. Но нагляднее ли это будет? На си решается так Код uint8_t GetChar(void) { uint8_t c;
if(Flag.SaveRollik) return 0; // Если идёт запись ролика, то выйти c=GetCharInStream(); if(c != METKA) return c; c=GetCharInStream(); // Взять следующий символ if(c != METKA){ Flag.ErrLoadKom = 1; // Ошибка приёма данных, - пришла команда Kom = c; // Досрочно } return c; }
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|