|
2.3, Vitto74 (ok), 00:53, 04/06/2018 [^] [^^] [^^^] [ответить]
| +21 +/– |
Плотно всеже засело правило - не использовать goto. Хотя смысл правила в том, чтобы этот самый goto не использовать там, где это может запутать код. Специально посмотрел исходник - никакой запутанности: goto используется только для упрощения кода. Например - что проще, такой код без goto
static int
csi_err_vset(struct csi_err *err, u_int code, int errnum, const char *fmt, va_list ap)
{
char *errmsg = NULL;
int rv = -1;
bool isError = false;
csi_err_clear(err);
err->code = code;
err->errnum = errnum;
if (vasprintf(&errmsg, fmt, ap) == -1) {
errmsg = NULL;
isError = true;
}
if ((errnum == -1) and (!isError)) {
err->msg = errmsg;
return (0);
}
if ((asprintf(&err->msg, "%s: %s", errmsg, strerror(errnum)) == -1) and (!isError)) {
err->msg = NULL;
isError = true;
}
if (!isError){
rv = 0;
}
free(errmsg);
return (rv);
}
или то, что мы видим в проекте?
static int
csi_err_vset(struct csi_err *err, u_int code, int errnum, const char *fmt, va_list ap)
{
char *errmsg = NULL;
int rv = -1;
csi_err_clear(err);
err->code = code;
err->errnum = errnum;
if (vasprintf(&errmsg, fmt, ap) == -1) {
errmsg = NULL;
goto err;
}
if (errnum == -1) {
err->msg = errmsg;
return (0);
}
if (asprintf(&err->msg, "%s: %s", errmsg, strerror(errnum)) == -1) {
err->msg = NULL;
goto err;
}
rv = 0;
err:
free(errmsg);
return (rv);
}
В libcsi код с goto явно менее запутан, чем получился бы без него. Поэтому говорить фу, на всё без исключения goto, есть крайность как и его необдуманное использование, а крайности как известно - плохо.
| |
|
3.4, PereresusNeVlezaetBuggy (ok), 01:33, 04/06/2018 [^] [^^] [^^^] [ответить]
| +1 +/– |
Именно так.
Важно помнить, что у каждого языка свои особенности, которые сказываются на «правилах хорошего тона», характерных для данного языка. В C, в отличие от большинства языков, у объектов нет автоматически вызываемых деструкторов, да и вообще объектов, с точки зрения ООП, нет. Поэтому если в высокоуровневом языке мы просто объявляем локальные переменные какого-нибудь типа string, или берём блокировку чем-то типа ReadLock lock(myMutex), то в C такого попросту нет. Это, фактически, обязывает явно выносить весь подчищающий код и код обработки ошибок в одно место — обычно это подвал функции.
Так что если бы это был C++, то — да, фу-фу-фу. Но это C, здесь другие правила.
| |
|
4.7, bOOster (ok), 07:45, 04/06/2018 [^] [^^] [^^^] [ответить]
| –1 +/– |
О чем пост то? Каким образом goto коррелирует к ООП?
Семантика циклов для C/C++/JAVA - одинакова.
if/break, while/break, for/break - в этом случае выход из цикла в одной точке. И все логика алгоритма линейно просматривается.
А если у тебя в цикле по условиям goto напиханы - например один выходит на инициализацию/начало цикла, второй где-то внутри цикла переходит, третий/четвертый выходит из цикла куда захочет - вот тут начинается бардак и катастрофа.
Так же из бардака - это переход по goto части кода, вперед, а потом по какому-то условию возврат в пропущенную часть.
И этот бардак справедлив как для С так и для C++
| |
|
5.8, PereresusNeVlezaetBuggy (ok), 09:10, 04/06/2018 [^] [^^] [^^^] [ответить]
| +2 +/– |
> О чем пост то? Каким образом goto коррелирует к ООП?
Таким, что в ООП-языках сама потребность в goto крайне низкая. Навскидку, в последних двух проектах на C++, которыми занимался, мне ни разу даже в голову не пришло использовать goto. В то же время в C — сплошь и рядом.
> Семантика циклов для C/C++/JAVA - одинакова.
> if/break, while/break, for/break - в этом случае выход из цикла в одной
> точке. И все логика алгоритма линейно просматривается.
В Java нет goto (хотя есть некоторое приближение с continue/break), во всяком случае, в нынешнем её виде (AFAIK, изначально тов. Гослинг такую штуку сделал, но потом отказался). Так что сравнение не совсем корректно. :) Но дело не в циклах, а прежде всего — в автоматических переменных. При выходе из области видимости у объектов в C++ начинают срабатывать деструкторы, которые могут освобождать ресурсы (память, блокировки и т.д.). Поэтому в C++ можно в большинстве случае просто влупить return. В C такого, по определению, нет, и всё надо освобождать-подчищать заново. И паттерн вида «if ((buf = malloc(size)) == NULL) goto err;» очень даже улучшает читаемость и (да простят мне не проснувшемуся это слово) сопровождаемость кода.
> А если у тебя в цикле по условиям goto напиханы - например
> один выходит на инициализацию/начало цикла, второй где-то внутри цикла переходит, третий/четвертый
> выходит из цикла куда захочет - вот тут начинается бардак и
> катастрофа.
> Так же из бардака - это переход по goto части кода, вперед,
> а потом по какому-то условию возврат в пропущенную часть.
> И этот бардак справедлив как для С так и для C++
Полностью согласен. Но речь-то изначально была не об этом, а о том, что в силу особенностей языка в C использование goto — обыденность. Как и любым инструментом, им можно сделать хорошо, а можно — не очень.
Г-н Vitto74, которому я отвечал, как раз привёл пример уместности goto — или вы эту уместность как раз хотите оспорить?
| |
|
4.9, nobody (??), 11:19, 04/06/2018 [^] [^^] [^^^] [ответить]
| +/– |
> В C, в отличие от большинства языков, у объектов нет автоматически вызываемых деструкторов
Эт в каких промышленных языках они есть кроме C++? Явовские убогие и неюзабельные финалайзеры к деструкторам не приплетать!
| |
|
|
6.11, nobody (??), 12:35, 04/06/2018 [^] [^^] [^^^] [ответить]
| +/– |
Ну тогда действительно "большинство", раз PHP. Ещё есть примеры?
(И это точно деструктор с детерминированной точкой вызова в коде программы, а не тот же финалайзер который "когда-нибудь" при сборке мусора. Вопрос без подвоха, просто интересно знать)
| |
|
7.13, PereresusNeVlezaetBuggy (ok), 14:36, 04/06/2018 [^] [^^] [^^^] [ответить]
| +/– |
> Ну тогда действительно "большинство", раз PHP. Ещё есть примеры?
Есть. Ada, Perl, Rust, с некоторой натяжкой D... дальше сами найдёте?
> (И это точно деструктор с детерминированной точкой вызова в коде программы, а
> не тот же финалайзер который "когда-нибудь" при сборке мусора. Вопрос без
> подвоха, просто интересно знать)
Да.
| |
|
|
5.15, Crazy Alex (ok), 08:11, 05/06/2018 [^] [^^] [^^^] [ответить]
| +/– |
Если не буквоедствовать - в джаве есть finally и GC, выполняющие примерно ту же функцию. Суть в том, что в C всё управление ресурсами приходится делать явным образом (нет средств автоматической уборки по выходу из скопа), и уход с помощью goto в конец функции, где это и происходит - чуть ли не единственное разумное решение.
| |
|
|
3.6, Аноним (-), 03:51, 04/06/2018 [^] [^^] [^^^] [ответить]
| –1 +/– |
> Хотя смысл правила в том, чтобы этот самый goto не использовать там, где это может запутать код
Всегда использовать goto сколько угодно обильно и не запутывать код. Но в определенный момент начинаются проблемы как бы самому не запутаться с именованием локальных переменных и их (пере-)использованием.
| |
|
2.12, proninyaroslav (ok), 13:26, 04/06/2018 [^] [^^] [^^^] [ответить]
| +2 +/– |
Достаточно посмотреть Linux kernel coding style, там отлично описано когда надо и когда не надо применять goto.
| |
|
3.16, Аноним (-), 09:32, 09/06/2018 [^] [^^] [^^^] [ответить]
| +/– |
>Достаточно посмотреть Linux kernel coding style, там отлично описано когда надо и когда не надо применять goto.
И статью в русской Википедии про goto.
| |
|
|
|