이 스레드에서 우리 goto
는 C 또는 C ++ 의 좋은 사용 예를 살펴 봅니다 . 사람들이 내가 농담이라고 생각했기 때문에 투표 한 답변 에서 영감을 얻었 습니다.
요약 (의도를 더 명확하게하기 위해 라벨이 원본에서 변경됨) :
infinite_loop:
// code goes here
goto infinite_loop;
대안보다 나은 이유 :
- 구체적입니다.
goto
무조건 분기를 일으키는 언어 구조입니다. 대안은 항상 참인 조건이 퇴화 된 조건부 분기를 지원하는 구조를 사용하는 것에 의존합니다. - 레이블은 추가 설명없이 의도를 문서화합니다.
- 독자는 초기
break
s를 위해 중간 코드를 스캔 할 필요가 없습니다 (비 원칙적인 해커가 초기 s로 시뮬레이션continue
하는 것은 여전히 가능합니다
goto
).
규칙 :
- gotophobes가 이기지 않은 척하십시오. 위의 내용은 기존 관용구에 위배되기 때문에 실제 코드에서 사용할 수 없습니다.
- 우리 모두가 ‘유해하다고 생각한 Goto’에 대해 들어 봤고 goto를 사용하여 스파게티 코드를 작성할 수 있다는 것을 알고 있다고 가정합니다.
- 예에 동의하지 않는 경우 기술적 장점만으로 비판하십시오 ( ‘사람들이 고토를 좋아하지 않기 때문에’는 기술적 이유가 아닙니다).
우리가 어른처럼 이야기 할 수 있는지 봅시다.
편집하다
이 질문은 이제 끝난 것 같습니다. 고품질 답변을 생성했습니다. 모든 사람, 특히 내 작은 루프 예제를 진지하게 받아 들인 사람들에게 감사합니다. 대부분의 회의론자들은 블록 범위의 부족을 우려했습니다. @quinmars가 주석에서 지적했듯이 언제든지 루프 본문을 중괄호로 묶을 수 있습니다. 그 전달에주의 for(;;)
하고 while(true)
(애 태우게하는 버그를 일으킬 수 있으며이를 생략) 당신이 중 하나를 무료로 중괄호를 제공하지 않습니다. 어쨌든,이 사소한 일에 더 이상 당신의 두뇌 전력의 낭비하지 않습니다 – 나는 무해하고 관용적으로 살 수 for(;;)
및 while(true)
(단지뿐만 아니라 내가 내 일을 유지하려는 경우).
다른 응답을 고려할 때 많은 사람들 goto
이 항상 다른 방식으로 다시 작성해야하는 것으로 간주하는 것을 봅니다 . 물론 goto
루프, 추가 플래그, 중첩 된 if
s 스택 등을 도입 하여을 피할 수 있지만 goto
작업에 가장 적합한 도구 인지 고려하지 않는 이유 는 무엇입니까? 다시 말해, 의도 된 목적을 위해 내장 된 언어 기능을 사용하는 것을 피하기 위해 사람들이 얼마나 추악함을 견딜 준비가되어 있습니까? 내 생각은 깃발을 추가하는 것조차도 지불하기에는 너무 비싸다는 것입니다. 나는 내 변수가 문제 또는 솔루션 영역에서 사물을 나타내는 것을 좋아합니다. ‘오로지 피하기 위해 goto
‘는 그것을 자르지 않습니다.
정리 블록으로 분기하기 위해 C 패턴을 부여한 첫 번째 답변을 수락합니다. IMO, 이것은 goto
게시 된 모든 답변 중 가장 강력한 경우를 만듭니다 .
답변
내가 사람들이 사용하는 것에 대해 들었던 한 가지 트릭이 있습니다. 나는 그것을 야생에서 본 적이 없다. 그리고 C ++에는 더 관용적으로이 작업을 수행하는 RAII가 있기 때문에 C에만 적용됩니다.
void foo()
{
if (!doA())
goto exit;
if (!doB())
goto cleanupA;
if (!doC())
goto cleanupB;
/* everything has succeeded */
return;
cleanupB:
undoB();
cleanupA:
undoA();
exit:
return;
}
답변
C에서 GOTO에 대한 고전적인 요구는 다음과 같습니다.
for ...
for ...
if(breakout_condition)
goto final;
final:
goto없이 중첩 된 루프에서 벗어나는 간단한 방법은 없습니다.
답변
다음은 신호에 의해 중단 될 수있는 Unix 시스템 호출에 대한 어리석지 않은 예제 (Stevens APITUE의)입니다.
restart:
if (system_call() == -1) {
if (errno == EINTR) goto restart;
// handle real errors
}
대안은 퇴화 루프입니다. 이 버전은 영어 “시스템 호출이 신호에 의해 중단 된 경우 다시 시작하십시오”와 같이 표시됩니다.
답변
Duff의 장치에 goto가 필요하지 않으면 당신도 마찬가지입니다! 😉
void dsend(int count) {
int n;
if (!count) return;
n = (count + 7) / 8;
switch (count % 8) {
case 0: do { puts("case 0");
case 7: puts("case 7");
case 6: puts("case 6");
case 5: puts("case 5");
case 4: puts("case 4");
case 3: puts("case 3");
case 2: puts("case 2");
case 1: puts("case 1");
} while (--n > 0);
}
}
위키 백과 항목 에서 위의 코드 .
답변
답변
매우 흔한.
do_stuff(thingy) {
lock(thingy);
foo;
if (foo failed) {
status = -EFOO;
goto OUT;
}
bar;
if (bar failed) {
status = -EBAR;
goto OUT;
}
do_stuff_to(thingy);
OUT:
unlock(thingy);
return status;
}
내가 사용하는 유일한 경우 goto
는 앞으로 점프하는 것입니다. 일반적으로 블록에서 벗어나 블록으로 들어 가지 않습니다. 이렇게하면 do{}while(0)
읽기 가능하고 구조화 된 코드를 유지하면서 중첩을 증가시키는 기타 구문의 남용을 방지 할 수 있습니다.
답변
나는 일반적으로 gotos에 반대하는 것이 없지만 언급 한 것처럼 루프에 사용하지 않는 몇 가지 이유를 생각할 수 있습니다.
- 범위를 제한하지 않으므로 내부에서 사용하는 임시 변수는 나중에까지 해제되지 않습니다.
- 범위를 제한하지 않으므로 버그가 발생할 수 있습니다.
- 범위를 제한하지 않으므로 나중에 동일한 범위의 코드에서 동일한 변수 이름을 다시 사용할 수 없습니다.
- 범위를 제한하지 않으므로 변수 선언을 건너 뛸 수 있습니다.
- 사람들은 그것에 익숙하지 않으며 코드를 읽기 어렵게 만듭니다.
- 이 유형의 중첩 루프는 스파게티 코드로 이어질 수 있으며 노멀 루프는 스파게티 코드로 이어지지 않습니다.