IT이야기

C 또는 C++의 좋은 gotos 예

cyworld 2022. 5. 3. 20:57
반응형

C 또는 C++의 좋은 gotos 예

이 실에서 우리는 의 좋은 이용 사례들을 살펴본다.gotoC 또는 C++로 표시한다.그것은 사람들이 내가 농담하는 것이라고 생각했기 때문에 투표한 답변에서 영감을 받았다.

요약(레이블이 원래에서 의도를 더욱 명확하게 하기 위해 변경됨):

infinite_loop:

    // code goes here

goto infinite_loop;

대안보다 더 나은 이유:

  • 구체적이다. goto무조건적인 가지를 야기하는 언어 구성이다.대안은 항상 참된 상태로 퇴보하는 조건부 분기를 지지하는 구조물의 사용에 의존한다.
  • 라벨은 별도의 설명 없이 의도를 문서화한다.
  • 판독기가 개입된 코드를 조기에 스캔할 필요가 없음breaks (원칙 없는 해커가 시뮬레이션하는 것은 여전히 가능하지만)continue일찍부터goto).

규칙:

  • 고토포비들이 이기지 못한 척 해.위와 같은 것은 확립된 관용어에 어긋나기 때문에 실제 코드로 사용할 수 없는 것으로 이해된다.
  • 우리 모두가 '해롭다고 생각하는 고토'에 대해 들어봤다고 가정하고, 고토가 스파게티 코드를 쓰는 데 사용될 수 있다는 것을 알고 있다.
  • 예를 들어 동의하지 않으면 기술적 장점만을 가지고 비판하라('사람들이 goto를 좋아하지 않기 때문에'는 기술적인 이유가 아니다).

어른들 처럼 이 얘기를 할 수 있는지 봅시다.

편집

이 문제는 이제 끝난 것 같다.그것은 몇 가지 고품질의 답을 만들어냈다.모두에게 고마워, 특히 내 작은 루프를 진지하게 본 사람들 말이야.대부분의 회의론자들은 블록 범위 부족에 대해 우려했다.@kinmars가 논평에서 지적했듯이, 당신은 언제나 루프 몸체에 브레이스를 둘 수 있다.나는 그것을 지나가는 것을 주목한다.for(;;)그리고while(true)치아 교정기를 공짜로 주지도 마라. (그리고 그것을 생략하는 것은 버그를 야기할 수도 있다.어쨌든, 나는 이 사소한 일로 너의 뇌력을 더 이상 낭비하지 않을 거야 - 나는 무해하고 관용적인 것으로 살 수 있어.for(;;)그리고while(true)(직장을 지키고 싶다면 그렇다.)

다른 응답들을 고려했을 때, 많은 사람들이goto항상 다른 방식으로 다시 써야 하는 것 처럼요물론 당신은 a를 피할 수 있다.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 없이 중첩된 루프를 탈출할 수 있는 간단한 방법은 없다.

여기 (Stevens APITUE로부터) 은근한 예를 들어보자. 유닉스 시스템 호출은 신호에 의해 중단될 수 있다.

restart:
    if (system_call() == -1) {
        if (errno == EINTR) goto restart;

        // handle real errors
    }

그 대안은 퇴보한 루프다.이 버전은 "시스템 호출이 신호에 의해 중단되었으면 다시 시작"이라고 영어로 되어 있다.

Duff의 장치가 goto가 필요하지 않다면, 너도 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에 반대되는 것은 없지만, 나는 당신이 언급했던 것과 같은 루프를 위해 gotos를 사용하지 않으려는 몇 가지 이유를 생각할 수 있다.

  • 범위를 제한하지 않으므로 내부에서 사용하는 모든 임시 변수는 나중에야 해제될 수 있다.
  • 그것은 버그를 야기할 수 있기 때문에 범위를 제한하지 않는다.
  • 범위를 제한하지 않으므로 동일한 범위의 향후 코드에서 동일한 변수 이름을 다시 사용할 수 없다.
  • 범위를 제한하지 않으므로 가변 선언을 건너뛸 수 있다.
  • 사람들은 그것에 익숙하지 않고 그것은 당신의 코드를 읽기 어렵게 만들 것이다.
  • 이런 유형의 내포된 루프는 스파게티 코드를 유발할 수 있으며, 노르말 루프는 스파게티 코드를 유발하지 않는다.

goto를 사용하기에 좋은 한 곳은 여러 지점에서 중단될 수 있는 절차로, 각 지점마다 다양한 수준의 정리가 필요하다.Gotophobes는 항상 구조화된 코드와 일련의 테스트로 Gotos를 대체할 수 있지만, 나는 이것이 과도한 삽입을 제거하기 때문에 더 간단하다고 생각한다.

(!openDataFile()인 경우)그만둘거야;
(!getDataFromFile()인 경우)goto closeFileAndQuit;
(!allocateSomeResources)goto freeResourcesAndQuit;
// 여기서 더 많은 작업을 수행...

freeResourcesAndQuit:// 사용 가능한 리소스closeFileAndQuit:// 파일 닫기종료:// 그만둬!

@fizzer.myopenid.com: 게시된 코드 조각은 다음과 같다.

    while (system_call() == -1)
    {
        if (errno != EINTR)
        {
            // handle real errors

            break;
        }
    }

나는 확실히 이 양식을 선호한다.

시간이 흐르면서 이런 패턴이 싫어졌음에도 불구하고, COM 프로그래밍으로 통합되어 있다.

#define IfFailGo(x) {hr = (x); if (FAILED(hr)) goto Error}
...
HRESULT SomeMethod(IFoo* pFoo) {
  HRESULT hr = S_OK;
  IfFailGo( pFoo->PerformAction() );
  IfFailGo( pFoo->SomeOtherAction() );
Error:
  return hr;
}

좋은 방법의 예는 다음과 같다.

// No Code

나는 정확하게 사용하는 것을 보았지만 상황은 보통이 아니게 추하다.의 사용일 때만 그렇다.goto그 자체는 원작보다 훨씬 덜 나쁘다.@Jonathon Holland의 문제점은 당신의 버전이 명확하지 않다는 것이다.사람들은 지역 변수를 두려워하는 것 같다.

void foo()
{
    bool doAsuccess = doA();
    bool doBsuccess = doAsuccess && doB();
    bool doCsuccess = doBsuccess && doC();

    if (!doCsuccess)
    {
        if (doBsuccess)
            undoB();
        if (doAsuccess)
            undoA();
    }
}

그리고 나는 이런 루프를 더 좋아하지만 어떤 사람들은 더 좋아한다.while(true).

for (;;)
{
    //code goes here
}

이것에 대해 내가 불평하는 것은 블록 범위를 잃는 것이다; 만약 루프가 끊어진다면, gotos 사이에 선언된 어떤 지역적 변수들은 여전히 유효하다. (아마 당신은 루프가 영원히 작동한다고 가정하고 있을 것이다; 나는 원래 질문 작성자가 그렇게 물어본 것은 아니라고 생각한다.)

범위 지정 문제는 C++에 더 큰 문제가 있는데, 어떤 물체는 적절한 시기에 그들의 dtor가 호출되는 것에 의존할 수 있기 때문이다.

내게 있어 goto를 사용하는 가장 좋은 이유는 멀티스텝 초기화 과정에서 실패하면 모든 init가 백업되는 것이 필수적이다.

if(!foo_init())
  goto bye;

if(!bar_init())
  goto foo_bye;

if(!xyzzy_init())
  goto bar_bye;

return TRUE;

bar_bye:
 bar_terminate();

foo_bye:
  foo_terminate();

bye:
  return FALSE;

나는 Goto의 나 자신을 사용하지 않는다. 그러나 나는 특정한 경우에 그것들을 사용할 수 있는 사람과 한 번 일을 했다.내가 정확히 기억한다면, 그의 근거는 성과 문제에 관한 것이었다 - 그는 또한 방법에 대한 구체적인 규칙을 가지고 있었다.항상 같은 기능을 하고, 라벨은 항상 goto 문 아래에 있었다.

#include <stdio.h>
#include <string.h>

int main()
{
    char name[64];
    char url[80]; /*The final url name with http://www..com*/
    char *pName;
    int x;

    pName = name;

    INPUT:
    printf("\nWrite the name of a web page (Without www, http, .com) ");
    gets(name);

    for(x=0;x<=(strlen(name));x++)
        if(*(pName+0) == '\0' || *(pName+x) == ' ')
        {
            printf("Name blank or with spaces!");
            getch();
            system("cls");
            goto INPUT;
        }

    strcpy(url,"http://www.");
    strcat(url,name);
    strcat(url,".com");

    printf("%s",url);
    return(0);
}

@Greg:

예를 들어 다음과 같이 하십시오.

void foo()
{
    if (doA())
    {    
        if (doB())
        {
          if (!doC())
          {
             UndoA();
             UndoB();
          }
        }
        else
        {
          UndoA();
        }
    }
    return;
}

참조URL: https://stackoverflow.com/questions/245742/examples-of-good-gotos-in-c-or-c

반응형