LINUX.ORG.RU

Потому что ломает code flow программы, так-же как и множественные return-ы, и код становится менее плаитичным.

fmjs
()

За исходными причинами - google for "Goto considered harmful". Типо, вместе с другими мероприятиями, увеличивает модульность кусков кода.

А сейчас это так, утратившее почти весь смысл правило хорошего тона. Вроде как за Зенит болеть.

Посмотри в исходники ядра - goto для обработки ошибок только так используется.

gods-little-toy ★★★
()

У Кнута есть неплохая статья, в которой он показывает, что goto в алголоподобных языках в той или иной форме необходим.

Miguel ★★★★★
()

Отлаживать программы с многочисленными goto - проще пристрелить того, кто их писал ;-).

В _редких_ случаях вариант с goto будет лучше, чем без него. Обычно указывают необходимость выхода из множества вложенных в друг друга циклов в сложных алгоритмах.

record ★★★★★
()
Ответ на: комментарий от record

> Обычно указывают необходимость выхода из множества вложенных в друг друга циклов в сложных алгоритмах.
А если речь идёт об условиях в циклической программе (речь в данном случае конкретно про jmp, goto я привёл для сравнения)
Т.е. эффективен ли джамп в таком коде:
if (..) {goto a}
if (..) {}
if (..) {}

// общий код
a: ..

в данном случае время обработки программы в rt-системе. сократится, т.к. второй и третий if обрабатываться не будут.

UVV ★★★★★
() автор топика
Ответ на: комментарий от UVV

>эффективен ли джамп

переход-то эффективен. Более того, использование goto может до предела оптимизировать алгоритм, только, что толку: через неделю, никто, включая автора, не сможет объяснить, как это все работает. И включить в программу доп. фичу становится очень проблематично. Если, конечно, это не учебный пример в одну страничку.

record ★★★★★
()
Ответ на: комментарий от UVV

было: (я ввел некие названия, для улучшения читабельности)

if (cond1) {goto a} 
if (cond2) {} 
if (cond3) {} 

// общий код 
do_something_before_lable();
a:
do_something_after_lable();

См и учись, тот-же код но без goto, скомпилируется скорее всего в такой-же 
бинарь, с точностью до бита:

if (!cond1) 
{
    if (cond2) {} 
    if (cond3) {} 
    // общий код 
    do_something_before_lable();
}
a:
do_something_after_lable();

fmjs
()
Ответ на: комментарий от UVV

> в данном случае время обработки программы в rt-системе. сократится, т.к. второй и третий if обрабатываться не будут.

А за использование goto в RT системах стоит увольнять.

fmjs
()

Я тоже воспользовался goto. Точный код я сейчас не помню, но смысл покажу:


if ((...)==-1) goto err; // -1 возвращается при ошибке
if ((...)==-1) goto err; // -1 возвращается при ошибке
if ((...)==-1) goto err; // -1 возвращается при ошибке
....
exit(0);

err:
... // тыр-пыр-8-дыр...
exit(1);

Можно ли писать так?

hibou ★★★★★
()
Ответ на: комментарий от kss

Упс, протупил и ляпнул фигню. Приношу свои искренние извинения.

kss ★★★★★
()
Ответ на: комментарий от UVV

Насколько я вспомнил, там создание сокета на стороне сервера было... множественное соединение не требовалось. Т.е. сервер и 1-н клиент.

hibou ★★★★★
()
Ответ на: комментарий от fmjs

> При включенном оптимизаторе, что-нибудь вроде -Os -- запросто.
Речь не о gcc и тем более не об i386.
Есть процессор и свой компилятор к нему.
Поэтому я речь веду с алгоритмической точки зрения.

UVV ★★★★★
() автор топика
Ответ на: комментарий от UVV

> Но на вложенный if уйдёт намного больше времени.

Вуаля:

1.c: 

#include <stdio.h>

int main()
{
        if (getc(stdin) == '0')
        {
                if (getc(stdin) == '1')
                        printf("first\n");
                if (getc(stdin) == '2')
                        printf("2nd\n");

                printf("do something before lable\n");
        }

        printf("do something after lable\n");

        return 0;
}

2.c:

#include <stdio.h>

int main()
{
        if (getc(stdin) != '0')
                goto a;
        if (getc(stdin) == '1') 
                printf("first\n");
        if (getc(stdin) == '2') 
                printf("2nd\n");

        printf("do something before lable\n");
a:      
        printf("do something after lable\n");
        
        return 0;
} 


Билдым: 

$ make CFLAGS=-Os 1
$ make CFLAGS=-Os 2

стрипаем:

$ strip 1 2

смотрим:

$ diff -u 1 2
$ ls -l 1 2 
-rwxr-xr-x   1 fmjs     fmjs     13668 Jul 13 13:55 1
-rwxr-xr-x   1 fmjs     fmjs     13668 Jul 13 13:55 2

$ gcc --version
powerpc-apple-darwin8-gcc-4.0.1 (GCC) 4.0.1 (Apple Computer, Inc. build 5250)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.



Итого, если в бинарном коде нет разницы, то откуда возмется "Но на вложенный if уйдёт намного больше времени."

fmjs
()
Ответ на: комментарий от UVV

> Есть процессор и свой компилятор к нему.

Подобного рода оптимизацию умеют производить 99% процентов компиляторов.

fmjs
()
Ответ на: комментарий от fmjs

> Подобного рода оптимизацию умеют производить 99% процентов компиляторов.

Вложенный if, если ты не используешь локальных переменных в блоке if-а, -- это всего-лишь ветка jump-ов/бренчей, аналогичная тому, что ты делешь ручками с goto. Никакого падения производительности тут не будет, если компилятор бонально умеет удалять ненужные аллокации фреймов стековых.

fmjs
()
Ответ на: комментарий от UVV

Ээээ.

А кто тебе сказал, что в _генерируемом_ коде jmp чем-то плох? Куда ж без него-то?

Сгенерированный ассемблер, все же, не каждый день читать приходится (а только при тонкой оптимизации и поиске ошибок в компиляторе); и от него требуется эффективность, а не понятность.

anonymous
()
Ответ на: комментарий от anonymous

это кто в асме избегает jmp ?
да они там на каждом шагу
без них просто никуда

kto_tama ★★★★★
()

Религии зло. Религия "не используйте goto" тоже зло.

Просто ко всему нужно подходить с головой. Штатные конструкции if/switch/while/do удобнее читать и анализировать, чем аналогичный код с goto.

Если можно обойтись штатными конструкциями (как тут выше было с if) и при этом не потерять читабельность и производительность, то лучше пользоваться ими. Если нельзя, то можно воспользоваться goto.

execve
()
Ответ на: комментарий от fmjs

А я немного изменю: if (cond1) { rv = -1; goto err; } if (cond2) { rv = -1; goto err; } if (cond3) { rv = -1; goto err; } ... if (condn) { rv = -1; goto err; }

do_ok();

err: cleanup(); if (rv) { .... } else { .... }

Теперь без goto. if (!cond1) { if (!cond2) { if (!cond3) { .... if (!condn) { } .... } } }

Отступы нереальные.

P.S. кроме того: #define ASSERT(some) \ do { \ if (!(some)) { \ rv = -1; \ goto err; \ } } while (0)

и: ASSERT(cond1); ASSERT(cond2); ...

P.P.S. Сам goto не использую почти никогда :)

rymis ★★
()
Ответ на: комментарий от fmjs

А я немного изменю:
if (cond1) { rv = -1; goto err; }
if (cond2) { rv = -1; goto err; }
if (cond3) { rv = -1; goto err; }
...
if (condn) { rv = -1; goto err; }

do_ok();

err:
     cleanup();
     if (rv) {
         ....
     } else {
         ....
     }

Теперь без goto.
if (!cond1) {
    if (!cond2) {
         if (!cond3) {
              ....
                                            if (!condn) {
                                            }
              ....
         }
    }
}

Отступы нереальные.

P.S. кроме того:
#define ASSERT(some) \
    do { \
        if (!(some)) { \
             rv = -1; \
             goto err; \
        }
    } while (0)

и:
ASSERT(cond1);
ASSERT(cond2);
...

P.P.S. Сам goto не использую почти никогда :)

rymis ★★
()
Ответ на: комментарий от rymis

> Теперь без goto. if (!cond1) { if (!cond2) { if (!cond3) { .... if (!condn) { } .... } } }

Подобные вещи, отцы советуют лечить пистолетом, поднесенным к своей голове, с последующим нажатием курка.

В подобных случаях, код рекомендуется разбивать на более мелкие логические блоки, а если это сложно выполнимо, ввиду того что "это особый случай", то тогда да, это особый случай, юзайте хоть goto, хоть longjump

fmjs
()
Ответ на: комментарий от rymis

> Теперь без goto.
> if (!cond1) {
>     if (!cond2) {
>          if (!cond3) {
>               ....
>                                             if (!condn) {
>                                             }
>               ....
>          }
>     }
> }

или

bool isOk = true;

if (isOk && !cond1) { rv = -1; isOk = false; }
if (isOk && !cond2) { rv = -1; isOk = false; }
if (isOk && !cond3) { rv = -1; isOk = false; }
if (isOk && !cond4) { rv = -1; isOk = false; }
if (isOk && !cond5) { rv = -1; isOk = false; }
if (isOk && !cond6) { rv = -1; isOk = false; }
if (isOk && !cond7) { rv = -1; isOk = false; }

if (isOk)
{
    do_ok();
}

fmjs
()
Ответ на: комментарий от fmjs

Абсолютно согласен, но такой вариант требует проверки (n-1) условия, а goto отвалится сразу.

А на тему отрывания различных частей тела:
struct info {
     part1_t * part1;
     part2_t * part2;
...
     partn_t * partn;
};

struct info * info_new(...)
{
     struct info * result;
     int res;

     result = malloc(...);
     result->part1 = part1_t_new();
     if (!result->part1) { res = -1; goto err; }
     ....
     result->partn = partn_t_new();
     if (!result->partn) { res = -1; goto err; }

     return result;
err:
     if (result->part1)
          part1_t_destroy(result->part1);
....
     free(result);
     return NULL;
}

Классическая ситуация создания объекта (например в GTK). Экзотика?

rymis ★★
()
Ответ на: комментарий от rymis

Неа, не экзотика. Это отсутствие поддежки исключений и автоматического выполнения деструкторов в языке.

На (ужасном, ужасном) Си-крест-крест такое решается созданием объектов на стеке внутри одного большого try-блока.

anonymous
()
Ответ на: комментарий от anonymous

Конечно. Я и не отрицаю, что на чистом Си бывает сложно писать, но это не говорит о том, что проектов на нем нет. Я против использования goto, но сказать, что использовать его нельзя, было бы неправильно.

А в быдло(Выберите язык со сборщиком мусора) вообще не возникло бы таких проблем :)

rymis ★★
()
Ответ на: комментарий от rymis

> А в быдло(Выберите язык со сборщиком мусора)

Например Быдло-лисп ?

> вообще не возникло бы таких проблем :)

в лиспе вроде goto есть... желающие - могут проблемы иметь :-)

gods-little-toy ★★★
()
Ответ на: комментарий от rymis

Как раз наоборот. Сборщики мусора пока что умеют собирать только память. А идиома "занятие ресурса == создание объекта на стеке" подразумевает вызов деструктора в предопределенное время.

Такое работает только при явном управлении памятью (или какой-то смешанной модели, типа "стековые удаляются при разрушении контекста, хиповые - гарбаж-коллектором" (кажется, в D так можно) или в случае рефренс-каунтинга, как в перле - но в перле порядок деструкции не определен).

anonymous
()

Дело привычки и задач.

Когда ты пишешь что-то очень-очень-очень низко, то goto твой верный друг, ибо позволяет, при грамотном использование, избежать дублирования кода (когда функциями оборачивать тяжелее).

Вообще goto не просто нельзя использовать, его нужно использовать! Но надо понимать когда стоит его использовать. Вот и все.

catap ★★★★★
()
Ответ на: комментарий от catap

> Когда ты пишешь что-то очень-очень-очень низко, то goto твой верный друг, ибо позволяет, при грамотном использование, избежать дублирования кода (когда функциями оборачивать тяжелее).

Только большая часть здещних обитателей говорящих о том, что goto полезен на low-level-е, никогда на этот low-level и не спускались :)

fmjs
()
Ответ на: комментарий от fmjs

> Только большая часть здещних обитателей говорящих о том, что goto полезен на low-level-е, никогда на этот low-level и не спускались :)
Ну вот я поэтому тему и создал, что сейчас я на этом уровне! ;-)

UVV ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.