Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Language agnostic 后藤仍然被认为是有害的吗?_Language Agnostic_Goto - Fatal编程技术网

Language agnostic 后藤仍然被认为是有害的吗?

Language agnostic 后藤仍然被认为是有害的吗?,language-agnostic,goto,Language Agnostic,Goto,每个人都知道Dijkstra的(还有.html文本和.pdf),从那时起,就有一个强大的推动力,就是尽可能避免goto声明。虽然可以使用goto生成无法维护的、杂乱无章的代码,但它仍然存在。即使是Scheme中的高级控制结构也可以被描述为复杂的goto 什么情况下可以使用goto?什么时候最好避免 作为后续问题:C提供了一对函数setjmp和longjmp,它们不仅能够在当前堆栈帧内,而且能够在任何调用帧内进行跳转。这些应该被视为像goto一样危险吗?更危险 迪克斯特拉本人对这个头衔感到遗憾,

每个人都知道Dijkstra的(还有.html文本和.pdf),从那时起,就有一个强大的推动力,就是尽可能避免goto声明。虽然可以使用goto生成无法维护的、杂乱无章的代码,但它仍然存在。即使是Scheme中的高级控制结构也可以被描述为复杂的goto

什么情况下可以使用goto?什么时候最好避免

作为后续问题:C提供了一对函数setjmp和longjmp,它们不仅能够在当前堆栈帧内,而且能够在任何调用帧内进行跳转。这些应该被视为像goto一样危险吗?更危险


迪克斯特拉本人对这个头衔感到遗憾,对此他不负责任。在(也是.pdf)的结尾,他写道:

最后是一个记录在案的短篇故事。 1968年,ACM的通信 在 标题“考虑的goto声明” “有害的”,在以后的岁月里 最常被提及的,, 然而,令人遗憾的是,往往是作者 除了它的名字,谁也没见过它 标题,这成为了我们的一个基石 通过成为模板,我的名声:我们 会看到各种各样的文章 标题“X被认为是有害的” 几乎任何X,包括一个标题为 “Dijkstra被认为是有害的”。但是 发生了什么事?我提交了一份 标题为“一宗针对 goto语句”,其中 为加快出版速度, 编辑变成了一封“致我的信” 在这个过程中,他 给它一个他自己的新名字 发明!编辑是尼克劳斯 沃思

唐纳德·E·克努特(Donald E.Knuth)撰写了一篇关于这一主题的深思熟虑的经典论文,与迪杰斯特拉(Dijkstra)的论文不谋而合。阅读既有助于重建语境,也有助于对主题的非教条式理解。在本文中,Dijkstra对本案的观点被报道,而且更为强烈:

唐纳德·克努斯:我认为 事实上,我并不反对这种观点 与迪杰克斯特拉的想法尖锐地一致,因为 他最近写道: “请不要落入 相信我非常 教条主义的关于[去那里]的 声明]。我有不舒服的感觉 感觉到别人在制造麻烦 宗教,好像 程序设计的概念问题 一个小把戏就可以解决 一种简单的编码规则形式!


原稿应该被认为是“无条件的被认为是有害的”。它特别提倡一种基于条件(
if
)和迭代(
while
)结构的编程形式,而不是早期代码常见的测试和跳转<代码>转到在某些语言或环境中仍然很有用,因为这些语言或环境中不存在适当的控制结构。

您可以使用它来中断深度嵌套的循环,但大多数情况下,您的代码可以重构为更干净的代码,而无需深度嵌套的循环

没有后藤这种东西被认为是有害的

GOTO是一种工具,与所有工具一样,它也可以被使用和滥用

然而,编程世界中有许多工具被滥用的倾向多于被使用的倾向,GOTO就是其中之一。德尔福的WITH语句是另一个例子

就个人而言,我在典型代码中不使用这两种方法,但我已经使用了GOTO和WITH这两种方法,这两种方法都是有保证的,另外一种解决方案应该包含更多的代码

最好的解决方案是编译器只需警告您关键字已被污染,并且您必须在语句周围填充几个pragma指令来消除警告


这就像告诉你的孩子不要拿剪刀跑一样。剪刀不错,但使用剪刀可能不是保持健康的最佳方式。

有时使用GOTO作为单个函数中异常处理的替代方法是有效的:

if (f() == false) goto err_cleanup;
if (g() == false) goto err_cleanup;
if (h() == false) goto err_cleanup;

return;

err_cleanup:
...

COM代码似乎经常陷入这种模式。

一种现代GOTO用法是由C#编译器为由yield return定义的枚举数创建状态机


GOTO应该由编译器而不是程序员使用。

我同意GOTO唯一可以使用的地方是当您需要处理错误时,并且发生错误的每个特定点都需要特殊处理

例如,如果您正在获取资源并使用信号量或互斥量,则必须按顺序获取它们,并且应始终以相反的方式释放它们

有些代码需要一种非常奇怪的模式来获取这些资源,而您不能仅仅编写一个易于维护和理解的控制结构来正确处理这些资源的获取和释放以避免死锁

在没有goto的情况下,总是可以正确地完成它,但是在本例和其他一些情况下,goto实际上是更好的解决方案,主要是为了可读性和可维护性

-亚当

我的一位同事说,使用GOTO的唯一原因是,如果你把自己编程到一个角落,这是唯一的出路。换句话说,提前进行正确的设计,以后就不需要使用GOTO了


我认为这部漫画很好地说明了“我可以重组程序的流程,或者用一个小的‘GOTO’来代替。”当你的设计很弱时,GOTO是一个很弱的出路。迅猛龙捕食弱者

我避免使用它,因为同事/经理无疑会在代码评审或偶然发现时质疑它的使用。虽然我认为它有用途(例如错误处理案例),但您将与其他开发人员发生冲突,他们将对它产生某种类型的问题

这不值得。

在《内核陷阱》中,与Linus Torvalds和一位“新人”讨论了在Linux代码中使用GOTOs的问题。这里有一些非常好的观点,还有莱纳斯
for{
  for{
    for{
      for{
        for{
          if(stuff){
            GOTO ENDOFLOOPS;
          }
        }
      }
    }
  }
}

ENDOFLOOPS:
3420 IF A > 2 THEN GOTO 1430
char run(char *pc) {
    void *opcodes[3] = {&&op_inc, &&op_lda_direct, &&op_hlt};
    #define NEXT_INSTR(stride) goto *(opcodes[*(pc += stride)])
    NEXT_INSTR(0);
    op_inc:
    ++acc;
    NEXT_INSTR(1);
    op_lda_direct:
    acc = ram[++pc];
    NEXT_INSTR(1);
    op_hlt:
    return acc;
}
a = b + 1
/* do something with a */
...
goto 10
...
a = b + 1
10: /* do something with a */
...
goto 10
...
if (some condition) {
  action-1
} else {
  action-2
}
request something
wait for it to be done
while some condition
    request something
    wait for it
    if one response
        while another condition
            request something
            wait for it
            do something
        endwhile
        request one more thing
        wait for it
    else if some other response
        ... some other similar sequence ...
    ... etc, etc.
endwhile
#define WAIT(n) do{state=(n); enque(this); return; L##n:;}while(0)
#define DONE state = -1

#define DISPATCH0 if state < 0) return;
#define DISPATCH1 if(state==1) goto L1; DISPATCH0
#define DISPATCH2 if(state==2) goto L2; DISPATCH1
#define DISPATCH3 if(state==3) goto L3; DISPATCH2
#define DISPATCH4 if(state==4) goto L4; DISPATCH3
... as needed ...
{
    DISPATCH4; // or as high a number as needed
    request something;
    WAIT(1); // each WAIT has a different number
    while (some condition){
        request something;
        WAIT(2);
        if (one response){
            while (another condition){
                request something;
                WAIT(3);
                do something;
            }
            request one more thing;
            WAIT(4);
        }
        else if (some other response){
            ... some other similar sequence ...
        }
        ... etc, etc.
    }
    DONE;
}
  YORN = ''
  LOOP
  UNTIL YORN = 'Y' OR YORN = 'N' DO
     CRT 'Is this correct? (Y/N) : ':
     INPUT YORN
  REPEAT
  IF YORN = 'N' THEN
     CRT 'Aborted!'
     STOP
  END
10:  CRT 'Is this Correct (Y)es/(N)o ':

     INPUT YORN

     IF YORN='N' THEN
        CRT 'Aborted!'
        STOP
     ENDIF
     IF YORN<>'Y' THEN GOTO 10
SomeObject someObject;    

if (someObject.IsComplex())    // this test is trivial
{
    // begin slow calculations here
    if (result of calculations)
    {
        // just discovered that I could use the fast calculation !
        goto Fast_Calculations;
    }
    // do the rest of the slow calculations here
    return;
}

if (someObject.IsmediumComplex())    // this test is slightly less trivial
{
    Fast_Calculations:
    // Do fast calculations
    return;
}

// object is simple, no calculations needed.
       do 10 i = 1,30
           ...blah...
           ...blah...
           if (k.gt.4) goto 37
91         ...blah...
           ...blah...
10     continue
       ...blah...
       return
37     ...some computation...
       goto 91
       ...blah...
       i = 1
       goto 76
123    ...blah...
       ...blah...
       i = 2
       goto 76
79     ...blah...
       ...blah...
       goto 54
       ...blah...
12     continue
       return
76     ...calculate something...
       ...blah...
       goto (123, 79) i
54     ...more calculation...
       goto 12
ptr = malloc(size);
if (!ptr) goto label_fail;
bytes_in = read(f_in,ptr,size);
if (bytes_in=<0) goto label_fail;
bytes_out = write(f_out,ptr,bytes_in);
if (bytes_out != bytes_in) goto label_fail;
success=false;
do {
    ptr = malloc(size);
    if (!ptr) break;
    bytes_in = read(f_in,ptr,size);
    if (count=<0) break;
    bytes_out = write(f_out,ptr,bytes_in);
    if (bytes_out != bytes_in) break;
    success = true;
} while (false);
100 IF NOT condition THEN GOTO 200
...stuff to do if condition is true...
190 GOTO 300
200 REM else
...stuff to do if condition is false...
300 REM end if