Comments 35
Опечатку в заголовке поправьте. Струкурное — это почти укурное :)
Коллега, Вы меня опередили, как раз собирался написать примерно то же самое.
В ряде случаев бывает удобно заменить каскадные if… elif… else простым switch по всем состояниям и в каждом case просто вычислять следующее состояние. В общем, классика автоматного прграммирования
В ряде случаев бывает удобно заменить каскадные if… elif… else простым switch по всем состояниям и в каждом case просто вычислять следующее состояние. В общем, классика автоматного прграммирования
yury@debian-dev-vm:~/kernel/linux-2.6.36-starterkit/mm$ grep goto *.c | wc -l
894
yury@debian-dev-vm:~/kernel/linux-2.6.36-starterkit/mm$ cat *.c | wc -l
75724
Право, меня удивляют бурления против goto :-)
ЗЫ. Это только в управлении памятью, всё ядро долго перебирать.
Да-да-да… Продолжим бурлить.
1) MSDN: It is good programming style to use the break, continue, and return statement in preference to goto whenever possible. Since the break statement only exits from one level of the loop, a goto may be necessary for exiting a loop from within a deeply nested loop. — Т.е. goto неплохо подходит для выхода сразу из нескольких циклов:
2) Финализация при помощи goto — а он быстро работает, и SEH не всегда помогает:
3) Поддержание принципа «один вход — один выход» при помощи goto:
4) Использование goto в машинно генерируемых кодах (всякого рода анализаторы, парсеры).
5) В C# оператор goto незаменим внутри switch;
6) И девушек обижать нехорошо:
…
И да, я склонен всё же к мнению такому (Джонсон М. Харт. Системное программирование в среде Windows, третье издание — 2005 г.): «Возможно, это дело вкуса, — то ли индивидуального, то ли корпоративного, — но многие программисты никогда не используют оператор goto и избегают употребления оператора break, кроме случаев его совместного использования с операторами switch и иногда — в циклах, а также совместного использования с операторами continue. Те, кто мыслит трезво, не спешат определять свою позицию в этом отношении. Обработчики завершения и исключений могут решать многие из тех задач, для решения которых вам хотелось бы привлечь оператор goto и операторы, снабжённые метками.»
1) MSDN: It is good programming style to use the break, continue, and return statement in preference to goto whenever possible. Since the break statement only exits from one level of the loop, a goto may be necessary for exiting a loop from within a deeply nested loop. — Т.е. goto неплохо подходит для выхода сразу из нескольких циклов:
#include <stdio.h>
int main()
{
int i, j;
for ( i = 0; i < 10; i++ )
{
printf_s( "Outer loop executing. i = %d\n", i );
for ( j = 0; j < 2; j++ )
{
printf_s( " Inner loop executing. j = %d\n", j );
if ( i == 3 )
goto stop;
}
}
// This message does not print:
printf_s( "Loop exited. i = %d\n", i );
stop:
printf_s( "Jumped to stop. i = %d\n", i );
}
* This source code was highlighted with Source Code Highlighter.
2) Финализация при помощи goto — а он быстро работает, и SEH не всегда помогает:
if (...)
goto Cleanup;
if (...)
goto Cleanup;
...
Cleanup:
...
* This source code was highlighted with Source Code Highlighter.
3) Поддержание принципа «один вход — один выход» при помощи goto:
int f()
{
int res;
// some code ...
if (...)
{
res = rand();
goto finish;
}
// some code ...
finish:
return res;
}
* This source code was highlighted with Source Code Highlighter.
4) Использование goto в машинно генерируемых кодах (всякого рода анализаторы, парсеры).
5) В C# оператор goto незаменим внутри switch;
6) И девушек обижать нехорошо:
…
И да, я склонен всё же к мнению такому (Джонсон М. Харт. Системное программирование в среде Windows, третье издание — 2005 г.): «Возможно, это дело вкуса, — то ли индивидуального, то ли корпоративного, — но многие программисты никогда не используют оператор goto и избегают употребления оператора break, кроме случаев его совместного использования с операторами switch и иногда — в циклах, а также совместного использования с операторами continue. Те, кто мыслит трезво, не спешат определять свою позицию в этом отношении. Обработчики завершения и исключений могут решать многие из тех задач, для решения которых вам хотелось бы привлечь оператор goto и операторы, снабжённые метками.»
интересно, что будет, когда противники goto узнают о setjmp и longjmp :-) и о ситуациях, когда они — единственный выход :-)
Например, в конторе, где я работал, занимаются сертификацией ПО управления электроникой самолётов по стандарту DO-178b. Пишут тесты. Приходит код, в коде — вечный цикл и вызов функции. Как провеить, что тело цикла корректно и не повиснуть? Как вариант, переопределить вызываемую функцию с тем, чтобы при втором вызове она делала longjmp (goto не поможет, т.к. другая функция) в место, не являющееся телом цикла, таким образом мы его завершим. Сам тестируемый код изменять, естественно, вообще нельзя. Исключение плюсовое бросать из вызываемой не получится, т.к. не плюсы :-)
Например, в конторе, где я работал, занимаются сертификацией ПО управления электроникой самолётов по стандарту DO-178b. Пишут тесты. Приходит код, в коде — вечный цикл и вызов функции. Как провеить, что тело цикла корректно и не повиснуть? Как вариант, переопределить вызываемую функцию с тем, чтобы при втором вызове она делала longjmp (goto не поможет, т.к. другая функция) в место, не являющееся телом цикла, таким образом мы его завершим. Сам тестируемый код изменять, естественно, вообще нельзя. Исключение плюсовое бросать из вызываемой не получится, т.к. не плюсы :-)
Главное, чтобы все понимали, что речь здесь идёт о си, а не о си++.
В си goto действительно нужен в этих местах, в си++ — не обязательно. (1) заменяется выносом в функцию, (2) RAII (с goto тупо не получится exception-safe) (3) много выходов, все довольны, т.к. 2, (4) машинно генерируемый код это вообще другой разговор, ровно как и (5) C#. Ну а с (6), конечно, не поспоришь, хотя там язык тоже другой: Р
В си goto действительно нужен в этих местах, в си++ — не обязательно. (1) заменяется выносом в функцию, (2) RAII (с goto тупо не получится exception-safe) (3) много выходов, все довольны, т.к. 2, (4) машинно генерируемый код это вообще другой разговор, ровно как и (5) C#. Ну а с (6), конечно, не поспоришь, хотя там язык тоже другой: Р
UFO just landed and posted this here
UFO just landed and posted this here
Хочу заметить в топике нет «бурления против goto». Зато в нем есть факт: многие программисты недолюбливают goto; авторитетное мнение: «Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете»; описание того, как можно избежать использования goto.
Я хоть и не любитель goto, но недавно пришлось отлаживать код примерно такой:
Представляете как это отлаживать, сколько дебага вставить надо перед каждым return?
Не проще ли именно с точки зрения поддержки и сопровождения кода писать как минимум
Сколько нервов съэкономит этот goto… хотя одно наличие подобного кода уже убивает.
if (a) {
...
...
return 1;
}
if (b) {
...
...
return 2;
}
...
повторить 15 раз в том же духе
Представляете как это отлаживать, сколько дебага вставить надо перед каждым return?
Не проще ли именно с точки зрения поддержки и сопровождения кода писать как минимум
if (что-то) {
result = 1;
goto Exit;
}
if (что-то еще) {
result = 2;
goto Exit;
}
...
повторить много раз
...
: Exit
write_debug("Result: " + result);
return result;
Сколько нервов съэкономит этот goto… хотя одно наличие подобного кода уже убивает.
Если в вашем примере убрать goto, то он будет выдавать тот же результат.
не факт
если («что-то» && «что-то еще») == true, то без goto результат будет 2, а с ним 1, else-ов ведь нет
если («что-то» && «что-то еще») == true, то без goto результат будет 2, а с ним 1, else-ов ведь нет
Не всегда, все зависит от реальных условий. Я собственно хотел показать только то, что при множетвенном ветвлении и куче return goto улучшает и читаемость, и отлаживаемость кода.
Это очень неплохо описано в замечательной книжке Алена Голуба, в русском переводе она называется «Правила программирования на С и С++» — перечитывал несколько раз, и хоть кое-что устарело, с чем-то не согласен — но вцелом это супер, каждый, кто хочет писать более-менее грамотный, читаемый и отлаживаемый код — должен ее прочитать. На просторах интернет ее можно найти например тут
Это очень неплохо описано в замечательной книжке Алена Голуба, в русском переводе она называется «Правила программирования на С и С++» — перечитывал несколько раз, и хоть кое-что устарело, с чем-то не согласен — но вцелом это супер, каждый, кто хочет писать более-менее грамотный, читаемый и отлаживаемый код — должен ее прочитать. На просторах интернет ее можно найти например тут
if (что-то) result = 1; else if (что-то еще) result = 2; ... повторить много раз ... write_debug("Result: " + result); return result;
В данном случае это то же самое, т.к. у вас при выполнении условия сразу происходит переход к отладочному выводу. Ваш код эквивалентен записи приведённого мной кода на ассемблере:
... ; вычисляем <что-то> и кладём в ebx test ebx, ebx jz L1 mov eax, 1 jmp Exit L1: ... ; вычисляем <что-то ещё> и кладём в ebx test ebx, ebx jz L2 mov eax, 2 jmp Exit L2: ... ; повторить много раз ... Exit: ... ; вызываем write_debug (result - в eax) ret
В общем, вы привели неудачный пример использования goto.
А если Вы делаете return изнутри цикла?
Или даже из пары вложенных циклов? Тут break (который по сути тот же goto к концу цикла) уже не поможет — он сработает на один цикл (хотя вроде поминалось, что в java можно и из вложенных выходить — но тогда опять же goto к концу внешнего цикла).
Так что goto иногда все-таки удобно.
Но не спорю, лучше бы его поменьше, и такие if'ы не писать.
Или даже из пары вложенных циклов? Тут break (который по сути тот же goto к концу цикла) уже не поможет — он сработает на один цикл (хотя вроде поминалось, что в java можно и из вложенных выходить — но тогда опять же goto к концу внешнего цикла).
Так что goto иногда все-таки удобно.
Но не спорю, лучше бы его поменьше, и такие if'ы не писать.
Мы как-то с друзьями спорили насчёт goto.
Решили посмотреть на самые популярные, проверенные временем программы, которыми пользуются миллионы разработчиков: исходники ядра линукс, llvm, gtk, gstreamer, android и т.д.
В каждой из этих программ используется goto.
По-моему, те кто фанатично боится goto — школьники, начитавшиеся букварей «не используйте goto, из-за этого взрываются компьютеры». goto — инструмент и, пользуясь им умело, можно сделать код читабельнее, легче в поддержке, структуринованнее.
Решили посмотреть на самые популярные, проверенные временем программы, которыми пользуются миллионы разработчиков: исходники ядра линукс, llvm, gtk, gstreamer, android и т.д.
В каждой из этих программ используется goto.
По-моему, те кто фанатично боится goto — школьники, начитавшиеся букварей «не используйте goto, из-за этого взрываются компьютеры». goto — инструмент и, пользуясь им умело, можно сделать код читабельнее, легче в поддержке, структуринованнее.
Оффтоп, но наболело.
Хабрэффект.ру становится все популярнее, все больше авторов выкладывают картинки к постам именно туда.
Но! Я этих картинок в упор не вижу :(
Иногда это терпимо, а иногда пост просто теряет смысл.
Возможно причина в том, что я не в России или СНГ.
Если это официальный хостинг хабра, то просьба к администрации разобраться, если нет, то просьба к авторам, используйте другой хостинг, пожалуйста.
Хабрэффект.ру становится все популярнее, все больше авторов выкладывают картинки к постам именно туда.
Но! Я этих картинок в упор не вижу :(
Иногда это терпимо, а иногда пост просто теряет смысл.
Возможно причина в том, что я не в России или СНГ.
Если это официальный хостинг хабра, то просьба к администрации разобраться, если нет, то просьба к авторам, используйте другой хостинг, пожалуйста.
У меня еще прикольнее: на работе картинки вижу, дома — нет. Думаю проблема не у хабраэффекта.
А официальный хостинг хабра таки хабрасторадж.орг
А официальный хостинг хабра таки хабрасторадж.орг
Или совсем избавиться от флага как это сделал eigrad здесь.
кажется, что вариант комменте по ссылке не верный — если условие b изначально '0', то хвост алгоритма (E) не выполнится ни разу.
Теперь построим цикл while do с заменой предикатных и функциональных блоков.я правильно понимаю, что на этой схеме получилось нечто похожее на машину состояний — switch, в котором каждый case это подпрограмма, представляющая собой либо выбор нового значения L (одного из двух) либо выполнение операции и назначение нового L?:
L = 1
white L > 0:
switch L:
case 1: if p1 L = 2 else L = 3 ; break
case 2: f1; L = 6 ; break
...
case 8: f5; L = 0 ; break
Для каждого j>0 заменить все присваивания L=j соответствующей подпрограммой Gj(в том числе и для L=1). Так как L больше никогда не будет присвоено значение j можно убрать проверку L=j (вместе с соответствующей ей веткой выполнения) из структуры программы.выглядит как «inline» подпрограмм? эта затея осуществима для всех j>0, в любом случае? или тут схема маягче: «Для каждого j>0 пытаться заменить все присваивания L=j… », и «Если L больше никогда не будет присвоено значение j ...». Просто в данном примере заменились не все присавивания — «L=3» в структуре осталось.
Sign up to leave a comment.
О структурном программировании