태그 보관물: c

c

C 또는 C ++에서 좋은 gotos의 예 [닫힌]

이 스레드에서 우리 goto는 C 또는 C ++ 의 좋은 사용 예를 살펴 봅니다 . 사람들이 내가 농담이라고 생각했기 때문에 투표 한 답변 에서 영감을 얻었 습니다.

요약 (의도를 더 명확하게하기 위해 라벨이 원본에서 변경됨) :

infinite_loop:

    // code goes here

goto infinite_loop;

대안보다 나은 이유 :

  • 구체적입니다. goto무조건 분기를 일으키는 언어 구조입니다. 대안은 항상 참인 조건이 퇴화 된 조건부 분기를 지원하는 구조를 사용하는 것에 의존합니다.
  • 레이블은 추가 설명없이 의도를 문서화합니다.
  • 독자는 초기 breaks를 위해 중간 코드를 스캔 할 필요가 없습니다 (비 원칙적인 해커가 초기 s로 시뮬레이션 continue하는 것은 여전히 가능합니다
    goto).

규칙 :

  • gotophobes가 이기지 않은 척하십시오. 위의 내용은 기존 관용구에 위배되기 때문에 실제 코드에서 사용할 수 없습니다.
  • 우리 모두가 ‘유해하다고 생각한 Goto’에 대해 들어 봤고 goto를 사용하여 스파게티 코드를 작성할 수 있다는 것을 알고 있다고 가정합니다.
  • 예에 동의하지 않는 경우 기술적 장점만으로 비판하십시오 ( ‘사람들이 고토를 좋아하지 않기 때문에’는 기술적 이유가 아닙니다).

우리가 어른처럼 이야기 할 수 있는지 봅시다.

편집하다

이 질문은 이제 끝난 것 같습니다. 고품질 답변을 생성했습니다. 모든 사람, 특히 내 작은 루프 예제를 진지하게 받아 들인 사람들에게 감사합니다. 대부분의 회의론자들은 블록 범위의 부족을 우려했습니다. @quinmars가 주석에서 지적했듯이 언제든지 루프 본문을 중괄호로 묶을 수 있습니다. 그 전달에주의 for(;;)하고 while(true)(애 태우게하는 버그를 일으킬 수 있으며이를 생략) 당신이 중 하나를 무료로 중괄호를 제공하지 않습니다. 어쨌든,이 사소한 일에 더 이상 당신의 두뇌 전력의 낭비하지 않습니다 – 나는 무해하고 관용적으로 살 수 for(;;)while(true)(단지뿐만 아니라 내가 내 일을 유지하려는 경우).

다른 응답을 고려할 때 많은 사람들 goto이 항상 다른 방식으로 다시 작성해야하는 것으로 간주하는 것을 봅니다 . 물론 goto루프, 추가 플래그, 중첩 된 ifs 스택 등을 도입 하여을 피할 수 있지만 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);
    }
}

위키 백과 항목 에서 위의 코드 .


답변

Knuth는 “GOTO 문을 사용한 구조화 된 프로그래밍”이라는 논문을 작성했습니다. 예를 들어 여기 에서 얻을 수 있습니다 . 거기에서 많은 예를 찾을 수 있습니다.


답변

매우 흔한.

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에 반대하는 것이 없지만 언급 한 것처럼 루프에 사용하지 않는 몇 가지 이유를 생각할 수 있습니다.

  • 범위를 제한하지 않으므로 내부에서 사용하는 임시 변수는 나중에까지 해제되지 않습니다.
  • 범위를 제한하지 않으므로 버그가 발생할 수 있습니다.
  • 범위를 제한하지 않으므로 나중에 동일한 범위의 코드에서 동일한 변수 이름을 다시 사용할 수 없습니다.
  • 범위를 제한하지 않으므로 변수 선언을 건너 뛸 수 있습니다.
  • 사람들은 그것에 익숙하지 않으며 코드를 읽기 어렵게 만듭니다.
  • 이 유형의 중첩 루프는 스파게티 코드로 이어질 수 있으며 노멀 루프는 스파게티 코드로 이어지지 않습니다.