루프와 함수를 지원하는 언어로 ‘goto’를 사용하는 것이 유리합니까? 그렇다면 왜 그렇습니까? 절대 사용해서는 안되는 인상을 오랫동안 받아왔다 .

나는 goto가능하면 절대 사용해서는 안되는 인상을 오랫동안 받아왔다 . 다른 날 libavcodec (C로 작성)를 숙독하면서 여러 번 사용하는 것을 알았습니다. goto루프와 함수를 지원하는 언어 로 사용 하는 것이 유리한가요 ? 그렇다면 왜 그렇습니까?



답변

내가 알고있는 “goto”문을 사용하는 데는 몇 가지 이유가 있습니다 (일부는 이미 이에 대해 언급했습니다).

기능을 완전히 종료

종종 함수에서 자원을 할당하고 여러 곳에서 종료해야 할 수도 있습니다. 프로그래머는 함수의 끝에 리소스 정리 코드를 넣어 코드를 단순화 할 수 있으며 함수의 모든 “종료 지점”이 정리 레이블로 이동합니다. 이런 식으로 함수의 “종료 지점”마다 정리 코드를 작성할 필요가 없습니다.

중첩 루프 종료

중첩 루프에 있고 모든 루프 를 해제해야하는 경우 goto는 break 문 및 if-check보다 훨씬 깨끗하고 간단합니다.

저수준 성능 개선

이것은 per-critical 코드에서만 유효하지만 goto 문은 매우 빠르게 실행되며 함수를 이동할 때 부스트를 줄 수 있습니다. 그러나 컴파일러는 일반적으로 gotos가 포함 된 코드를 최적화 할 수 없기 때문에 양날의 검입니다.

이 모든 예에서 gotos는 단일 기능의 범위로 제한됩니다.


답변

gotoEdsger Dijkstra의 GoTo 고려 된 유해한 기사는 직간접 적으로 반박하는 모든 사람이 자신의 입장을 입증합니다. 너무 나쁜 Dijkstra의 기사는 요즘 문이 사용되는 방식과 거의 관련goto 이 없으므로 기사의 내용은 현대 프로그래밍 장면에는 거의 적용되지 않습니다. 그만큼goto 없는 밈은 이제 종교, 즉 대제사장과 지각 된 이단자들의 떨림 (또는 더 나쁘게)에서 지시 된 경전까지 거슬러 올라갑니다.

Dijkstra의 논문을 맥락에 두어 주제에 대해 약간의 조명을 줍시다.

Dijkstra가 그의 논문을 썼을 때 당시 인기있는 언어는 BASIC, FORTRAN (이전 방언) 및 다양한 어셈블리 언어와 같은 구조화되지 않은 절차 적 언어였습니다. 고급 언어를 사용하는 사람들 은 “스파게티 코드”라는 용어를 일으킨 뒤틀리고 뒤틀린 실행 스레드로 코드베이스 전체 를 뛰어 넘는 것이 일반적이었습니다 . 마이크 메이필드 (Mike Mayfield)가 쓴 클래식 트렉 (Trek) 게임 에 뛰어 들어 어떻게 작동하는지 알아 내면이 사실을 알 수 있습니다. 잠시 살펴보고 살펴보십시오.

이건 다 익스트라는 1968 년 자신의 논문에 대해 난간되었다 “문에 이동의 억제되지 않은 사용”입니다 즉 그 논문을 쓰는 그를 주도 그가 살았던 환경입니다. 원하는 시점에서 코드에서 원하는 곳으로 이동할 수있는 능력은 그가 비판하고 멈추라는 요구였습니다. 이를 gotoC 나 다른 현대 언어 의 빈약 한 힘과 비교하는 것은 간단합니다.

나는 이단자들이 직면 한 컬 티스트들의 노래를 이미들을 수있다. “하지만 gotoC에서 코드를 읽기가 매우 어려울 수 있습니다 .” 오 예? 코드 없이도 코드를 읽기 어렵게 만들 수 있습니다 goto. 이 같은:

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

a는 아니 goto눈에, 그래서 쉽게 바로 읽을 수 있어야합니다? 아니면 어떻습니까?

a[900];     b;c;d=1     ;e=1;f;     g;h;O;      main(k,
l)char*     *l;{g=      atoi(*      ++l);       for(k=
0;k*k<      g;b=k       ++>>1)      ;for(h=     0;h*h<=
g;++h);     --h;c=(     (h+=g>h     *(h+1))     -1)>>1;
while(d     <=g){       ++O;for     (f=0;f<     O&&d<=g
;++f)a[     b<<5|c]     =d++,b+=    e;for(      f=0;f<O
&&d<=g;     ++f)a[b     <<5|c]=     d++,c+=     e;e= -e
;}for(c     =0;c<h;     ++c){       for(b=0     ;b<k;++
b){if(b     <k/2)a[     b<<5|c]     ^=a[(k      -(b+1))
<<5|c]^=    a[b<<5      |c]^=a[     (k-(b+1     ))<<5|c]
;printf(    a[b<<5|c    ]?"%-4d"    :"    "     ,a[b<<5
|c]);}      putchar(    '\n');}}    /*Mike      Laman*/

아니 goto하나있다. 따라서 읽을 수 있어야합니다.

이 예제에서 내 요점은 무엇입니까? 읽을 수없고 유지할 수없는 코드를 만드는 언어 기능은 아닙니다. 그것을하는 것은 구문이 아닙니다. 이것을 일으키는 것은 나쁜 프로그래머입니다. 위의 항목에서 알 수 있듯이 나쁜 프로그래머는 모든 언어 기능을 읽을 수없고 사용할 수 없게 만들 있습니다. for거기 루프 처럼 . (알 겠어요?)

공정하게 말하면, 일부 언어 구성은 다른 언어 구성보다 남용하기가 더 쉽습니다. 그러나 C 프로그래머라면, 나는 #define십자군 전쟁에 나서기 전에 오래 사용하는 것의 약 50 %를 훨씬 더 가까이 들여다 보아야한다 goto!

따라서 지금까지이 책을 읽고 자하는 사람들에게는 몇 가지 중요한 사항이 있습니다.

  1. 에 다 익스트라의 논문 goto문은 프로그래밍 환경을 위해 작성되었습니다 goto했다 훨씬
    더 가능성이 어셈블러없는 가장 현대적인 언어보다 손상.
  2. goto이 때문에 모든 용도를 자동으로 버리는 것은 “한 번 재미를 보려고했지만 마음에 들지 않았으므로 지금은 반대한다”고 말하는 것이 합리적입니다.
  3. goto다른 구문으로 적절하게 대체 할 수없는 코드에서 현대적인 (비유 기적) 구문을 합법적으로 사용합니다 .
  4. 물론 동일한 진술의 불법적 인 사용이 있습니다.
  5. “- godo” 대신에 항상 거짓 do루프가 사용되지 않는 ” “abomination 과 같은 현대적인 제어문도 불법적 으로 사용 break됩니다 goto. 이것들은 종종 신중하게 사용하는 것보다 더 나쁩니다 goto.

답변

모범 사례를 맹목적으로 따르는 것은 모범 사례가 아닙니다. goto흐름 제어의 기본 형태 인 문장 을 피하는 아이디어는 읽을 수없는 스파게티 코드를 생성하지 않는 것입니다. 적절한 장소에서 드물게 사용하는 경우 아이디어를 표현하는 가장 단순하고 명확한 방법 일 수 있습니다. Zortech C ++ 컴파일러 및 D 프로그래밍 언어의 작성자 인 Walter Bright는이를 자주 사용하지만 신중하게 사용합니다. goto그의 진술 에도 불구하고 그의 코드는 여전히 완벽하게 읽을 수 있습니다.

결론 : 피하기 goto위해 피하는 goto것은 의미가 없습니다. 실제로 피하고 싶은 것은 읽을 수없는 코드를 생성하는 것입니다. 귀하의 경우 goto-laden 코드를 읽을 수있는, 다음에 아무것도 잘못이있다.


답변

goto프로그램 흐름 1 (일명“스파게티 코드”) 에 대한 추론을 하기 때문에 goto일반적으로 누락 된 기능을 보상하는 데만 사용됩니다. goto실제로 사용할 수는 있지만 언어가 더 체계적인 변형을 제공하지 않는 경우에만 사용할 수 있습니다. 같은 목표. 의심의 예를 보자.

우리가 사용하는 goto의 규칙은 goto가 함수의 단일 종료 정리 지점으로 건너 뛰는 것이 좋습니다.

이는 사실이지만 언어가 정리 코드 (예 : RAII 또는 finally )를 작업을 위해 특별히 구축 된 경우와 동일) 또는 합당한 이유가없는 경우에만 가능합니다. 구조적 예외 처리를 사용합니다 (그러나 매우 낮은 수준을 제외 하고는이 경우가 없습니다).

대부분의 다른 언어에서 허용되는 유일한 사용은 goto중첩 루프를 종료하는 것입니다. 심지어 외부 루프를 자체 방법으로 들어 올려 return대신 사용하는 것이 거의 항상 좋습니다 .

그 외에는 goto특정 코드에 대해 충분히 생각하지 못했다는 표시가 있습니다.


1goto 일부 제한 사항 (예 : goto기능에 뛰어 들거나 벗어날 수 없음)을 구현 하도록 지원 하는 현대 언어 는 근본적으로 동일하게 유지됩니다.

또한 다른 언어 기능, 특히 예외는 마찬가지입니다. 예외가 아닌 프로그램 흐름을 제어하기 위해 예외를 사용하지 않는 규칙과 같이 표시된 경우에만 이러한 기능 만 사용하는 엄격한 규칙이 있습니다.


답변

글쎄요, 항상 나쁜 것 하나가 있습니다 goto's; 이동을 피하기 위해 다른 프로그램 흐름 연산자의 이상한 사용 :

예 :

    // 1
    try{
      ...
      throw NoErrorException;
      ...
    } catch (const NoErrorException& noe){
      // This is the worst
    }


    // 2
    do {
      ...break;
      ...break;
    } while (false);


    // 3
    for(int i = 0;...) {
      bool restartOuter = false;
      for (int j = 0;...) {
        if (...)
          restartOuter = true;
      if (restartOuter) {
        i = -1;
      }
    }

etc
etc


답변

에서 C #의 스위치도다 가을-을 통해 수 없습니다 . 따라서 goto 는 제어를 특정 스위치 케이스 레이블 또는 기본 레이블 로 전송하는 데 사용됩니다 .

예를 들면 다음과 같습니다.

switch(value)
{
  case 0:
    Console.Writeln("In case 0");
    goto case 1;
  case 1:
    Console.Writeln("In case 1");
    goto case 2;
  case 2:
    Console.Writeln("In case 2");
    goto default;
  default:
    Console.Writeln("In default");
    break;
}

편집 : “경과 없음”규칙에는 한 가지 예외가 있습니다. 사례 설명에 코드가없는 경우 대체가 허용됩니다.


답변

#ifdef TONGUE_IN_CHEEK

Perl에는 goto가난한 사람의 꼬리 호출을 구현할 수 있는 기능 이 있습니다. :-피

sub factorial {
    my ($n, $acc) = (@_, 1);
    return $acc if $n < 1;
    @_ = ($n - 1, $acc * $n);
    goto &factorial;
}

#endif

좋아, 그래서 C와는 아무런 관련이 없습니다 goto. 더 진지하게, 나는 goto청소 를 위해 사용 하거나 더프의 장치 등 을 구현 하는 것에 대한 다른 의견에 동의합니다 . 학대가 아닌 사용에 관한 것입니다.

예를 들어 완전히 예외가 아닌 상황에서 완전히 중첩 된 제어 구조를 피하기 위해 예외를 던지는 경우와 같이 동일한 주석이 longjmp, 예외 등에 적용 call/cc할 수 있습니다. .)