[language-agnostic] GOTO는 여전히 해로운 것으로 간주됩니까? [닫은]

누구나 편집자에게 보낸 Dijkstra의 편지를 알고 있습니다 : 유해한 것으로 간주되는 진술 ( 여기서는 .html 스크립트 및 .pdf)로 이동 하십시오 . goto를 사용하여 유지 관리 할 수없는 거대한 코드를 생성 할 수는 있지만 최신 프로그래밍 언어로 유지 됩니다 . Scheme 의 고급 연속 제어 구조 조차도 정교한 goto로 설명 할 수 있습니다.

어떤 상황에서 goto를 사용해야합니까? 언제 피하는 것이 가장 좋습니까?

후속 질문 : C는 setjmp와 longjmp의 한 쌍의 함수를 제공하여 현재 스택 프레임뿐만 아니라 호출 프레임 내에서도 이동할 수 있습니다. 이것들은 goto만큼 위험한 것으로 간주되어야합니까? 더 위험한?


Dijkstra는 자신이 책임을지지 않은 제목을 후회했습니다. 의 끝에서 EWD1308 (또한 여기 .PDF) 그가 쓴 :

마지막으로 레코드에 대한 짧은 이야기. 1968 년 ACM의 커뮤니케이션은 ” 유해한 것으로 간주되는 goto 성명서 “라는 제목으로 내 텍스트를 출판 했다. 제목은 템플릿이되어 내 명성의 초석이되었습니다. “Dijkstra는 유해한 것으로 간주”라는 제목을 포함하여 거의 모든 X에 대해 “X는 유해한 것으로 간주”라는 제목의 모든 기사를 볼 수 있습니다. 그러나 무슨 일이 있었습니까? 제목이 ‘ 고토 진술에 대한 사례 ‘인 논문을 제출했습니다 .“, 출판 속도를 높이기 위해 편집자는”편집자에게 편지 “로 바뀌었고, 그 과정에서 그는 자신의 발명품에 새로운 제목을 부여했습니다! 편집자는 Niklaus Wirth였습니다.

Dijkstra의 주제와 일치하는이 주제에 대해 잘 알려진 고전 논문은 Donald E. Knuth의 Statements to go with Statements로 구성된 Structured Programming입니다 . 두 가지를 모두 읽으면 상황에 대한 맥락과 비 도움적인 주제에 대한 이해를 회복하는 데 도움이됩니다. 이 백서에서이 사례에 대한 Dijkstra의 의견이보고되었으며 더욱 강력합니다.

Donald E. Knuth : 저는 그러한 견해를 제시함으로써 Dijkstra의 아이디어에 대해 최근에 다음과 같은 글을 썼기 때문에 실제로 동의하지 않는 것은 아니라고 생각합니다. ] 문으로 이동합니다. 내가 프로그래밍의 개념 문제를 규율을 코딩 간단한 형태로, 하나의 속임수에 의해 해결 될 수 있다면 다른 사람이, 그것의 종교를하고 있다는 불편한 느낌이!



답변

다음 내용은 일반화입니다. 예외를 항소하는 것이 항상 가능하지만 일반적으로 (나의 경험과 겸손한 의견으로는) 위험의 가치가 없습니다.

  1. 메모리 주소 (GOTO 또는 원시 포인터)를 제한없이 사용하면 쉽게 피할 수있는 실수를 할 수있는 기회가 너무 많습니다.
  2. 코드에서 특정 “위치”에 도달하는 방법이 많을수록 시스템의 상태에 대한 확신이 줄어 듭니다. (아래 참조)
  3. 구조화 된 프로그래밍 IMHO는 “GOTO를 피하는 것”이 ​​아니라 코드의 구조를 데이터의 구조와 일치시키는 것에 관한 것입니다. 예를 들어, 반복적 인 데이터 구조 (예를 들어, 배열, 순차 파일 등)는 반복되는 코드 단위에 의해 자연스럽게 처리된다. 내장 구조 (예를 들어, 동안, 동안, 각, 등)를 가짐으로써 프로그래머는 동일한 진부한 코드 패턴을 반복하는 지루함을 피할 수 있습니다.
  4. GOTO가 저수준 구현 세부 사항 (항상 그런 것은 아닙니다!)이더라도 프로그래머가 생각 해야하는 수준보다 낮습니다. 원시 바이너리로 개인 수표 책의 균형을 잡는 프로그래머는 몇 명입니까? 데이터베이스 엔진에 키를 제공하는 대신 디스크의 어떤 섹터에 특정 레코드가 포함되어 있는지 걱정하는 프로그래머는 몇 명입니까 (실제 디스크 섹터로 모든 프로그램을 실제로 작성하면 문제가 발생할 수있는 방법은 몇 가지입니까)?

위의 각주 :

포인트 2와 관련하여 다음 코드를 고려하십시오.

a = b + 1
/* do something with a */

코드의 “무언가”지점에서 a보다 큰 확신을 가지고 진술 할 수 있습니다 b. (예, 트랩되지 않은 정수 오버플로의 가능성을 무시하고 있습니다. 간단한 예를 보지 않겠습니다.)

반면에 코드가 이런 식으로 읽은 경우 :

...
goto 10
...
a = b + 1
10: /* do something with a */
...
goto 10
...

라벨 10에 도달하는 다양한 방법 은 그 시점 ab그 시점 의 관계에 대해 확신하기 위해 훨씬 더 열심히 노력해야한다는 것을 의미합니다 . (실제로 일반적인 경우 결정 불가능합니다!)

포인트 4와 관련하여 코드에서 “어딘가에 가고있다”는 전체 개념은 은유 일뿐입니다. 전자와 광자 (폐열에 대한 것)를 제외하고 CPU 내부에는 실제로 “가는”것이 없습니다. 때때로 우리는 더 유용한 다른 하나에 대한 은유를 포기합니다. 나는 수십 년 전에 언어를 만나는 것을 기억합니다.

if (some condition) {
  action-1
} else {
  action-2
}

가상 머신에서 action-1 및 action-2를 라인 외부 매개 변수없는 루틴으로 컴파일 한 다음 조건의 부울 값을 사용하여 하나의 다른 인수를 사용하는 단일 2 개의 인수 VM opcode를 사용하여 가상 머신에서 구현되었습니다. 그 개념은 단순히 “여기에 가거나 거기에 가라”보다는 “지금 무엇을 부를 것인지 선택”이었습니다. 다시, 은유의 변화.


답변

XKCD의 GOTO 코믹

내 동료가 GOTO를 사용하는 유일한 이유는 당신이 구석 구석까지 자신을 프로그래밍 할 수있는 유일한 방법이라고 말했다. 다시 말해, 적절한 디자인을 미리하고 나중에 GOTO를 사용할 필요가 없습니다.

나는이 만화가 아름답게 “프로그램 흐름을 재구성하거나 작은 ‘GOTO’를 대신 사용할 수있다”고 설명했다. 디자인이 약한 경우 GOTO는 약한 방법입니다. Velociraptors는 약점을 먹습니다 .


답변

때때로 단일 함수 내에서 예외 처리에 대한 대안으로 GOTO를 사용하는 것이 유효합니다.

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

return;

err_cleanup:
...

COM 코드는이 패턴에 상당히 자주 빠지는 것 같습니다.


답변

goto를 사용하여 한 번만 기억할 수 있습니다. 나는 일련의 5 개의 중첩 된 루프를 가지고 있었고 특정 조건에 따라 초기부터 전체 구조를 깨뜨릴 수 있어야했습니다.

for{
  for{
    for{
      for{
        for{
          if(stuff){
            GOTO ENDOFLOOPS;
          }
        }
      }
    }
  }
}

ENDOFLOOPS:

부울 브레이크 변수를 쉽게 선언하고 각 루프에 대한 조건부로 사용했지만 GOTO가 실용적이고 읽기 쉬운 것으로 결정했습니다.

벨로시 랩터가 나를 공격하지 않았습니다.


답변

우리는 이미이 토론을 했고 나는 입장을 고수 합니다 .

또한, 나는 고급 언어 구조를 ” goto변장 중” 으로 묘사하는 사람들에게 지겨워한다. 왜냐하면 그들은 전혀 요점 얻지 못했기 때문이다 . 예를 들면 다음과 같습니다.

Scheme의 고급 연속 제어 구조조차도 정교한 goto로 설명 할 수 있습니다.

그건 말도 안되는 말이야 모든 제어 구조는 관점에서 구현 될 수 goto있지만이 관찰은 전혀 사소하고 쓸모가 없습니다. goto긍정적 인 효과로 인해 유해한 것으로 간주되지는 않지만 부정적인 결과로 인해 구조화 된 프로그래밍에 의해 제거되었습니다.

마찬가지로“GOTO는 도구이며 모든 도구가 사용하고 남용 할 수 있습니다”라는 문구가 완전히 표시되지 않습니다. 현대의 건설 노동자는 바위를 사용하지 않고“도구”라고 주장하지 않습니다. 바위는 망치로 대체되었습니다. goto제어 구조로 대체되었습니다. 만약 건설 노동자가 망치없이 야생에서 좌초된다면, 그는 대신 바위를 사용할 것입니다. 프로그래머가 기능 X가없는 열등한 프로그래밍 언어를 사용해야하는 경우에는 물론 goto대신 사용해야 합니다. 그러나 적절한 언어 기능 대신 다른 곳에서 사용하면 언어를 제대로 이해하지 못하고 잘못 사용합니다. 정말 간단합니다.


답변

Goto는 그것을 위해 프로그램에 포함시킬 것들의 목록이 매우 낮습니다. 그렇다고 받아 들일 수없는 것은 아닙니다.

Goto는 상태 머신에 적합 할 수 있습니다. 루프의 switch 문은 (일반적으로 중요한 순서대로) 다음과 같습니다. (a) 실제로 제어 흐름을 나타내지 않음, (b) 못생긴, (c) 언어 및 컴파일러에 따라 잠재적으로 비효율적입니다. 따라서 상태 당 하나의 함수를 작성하고 “return NEXT_STATE;”와 같은 작업을 수행하게됩니다. 심지어 고토처럼 보입니다.

물론 상태 머신을 이해하기 쉬운 방식으로 코딩하는 것은 어렵습니다. 그러나 이러한 어려움 중 어느 것도 goto를 사용하는 것과 관련이 없으며 대체 제어 구조를 사용하여 줄일 수는 없습니다. 귀하의 언어에 ‘상태 기계’구성이없는 한. 광산은 그렇지 않습니다.

드문 경우에 알고리즘이 더 구체적인 제어 흐름 (루프, 조건부, 그렇지 않은 것)이 아닌 제한된 허용 가능한 전환 세트 (고 토스)로 연결된 일련의 노드 (상태)를 통한 경로로 가장 이해하기 쉬운 경우 ), 코드에서 명시 적이어야합니다. 그리고 당신은 예쁜 다이어그램을 그려야합니다.

setjmp / longjmp는 예외 또는 예외와 유사한 동작을 구현하는 데 유용 할 수 있습니다. 보편적으로 칭찬되지는 않지만 예외는 일반적으로 “유효한”제어 구조로 간주됩니다.

setjmp / longjmp는 올바르게 사용하기가 어렵다는 점에서 goto보다 ‘더 위험합니다’.

나쁜 코드를 작성하는 것이 가장 어려운 언어는 없었습니다. -도널드 크 누스

C에서 고토를 복용하는 것이 쉬워 C.에서 사실 좋은 코드를 작성하지 것이다, 오히려 C가되는 시점을 놓칠 되어 영광 어셈블러 언어의 역할을 할 수 있어야한다.

다음은 “유해한 것으로 간주되는 포인터”, “유해한 것으로 간주되는 덕 타이핑”입니다. 그러면 안전하지 않은 프로그래밍 구조를 제거 할 때 누가 당신을 변호해야합니까? 뭐라고?


답변

에서 리눅스 : 커널 코드에서 고토를 사용하여 커널 트랩에, 리누스 토발즈 (Linus Torvalds)와 리눅스 코드 GOTOs의 사용에 대한 “새로운 남자”와 토론이있다. 거기에 아주 좋은 점이 있으며 Linus는 일반적인 오만을 입었습니다. 🙂

일부 구절 :

Linus : “아니, 당신은 Niklaus Wirth가 실제로 자신이 무슨 말을하는지 알고 있다고 생각하는 CS 사람들에 의해 세뇌를당했습니다. 그는 몰랐습니다.

Linus : “고토는 괜찮고, 많은 양의 들여 쓰기보다 더 읽기 쉽다고 생각합니다.”

Linus : “물론 레이블을 설명 할 수없는 파스칼과 같은 어리석은 언어에서는 goto가 잘못 될 수 있습니다.”