C 또는 C ++에서 좋은 gotos의 예
이 스레드에서 우리 goto
는 C 또는 C ++ 의 좋은 사용 예를 살펴 봅니다 . 사람들이 내가 농담이라고 생각했기 때문에 투표 한 답변 에서 영감을 얻었 습니다.
요약 (의도를 더 명확하게하기 위해 라벨이 원본에서 변경됨) :
infinite_loop:
// code goes here
goto infinite_loop;
대안보다 나은 이유 :
- 구체적입니다.
goto
무조건 분기를 일으키는 언어 구조입니다. 대안은 항상 참인 조건이 퇴화 된 조건부 분기를 지원하는 구조를 사용하는 것에 의존합니다. - 레이블은 추가 설명없이 의도를 문서화합니다.
- 독자는 초기의 중간에 코드를 스캔 할 필요가 없습니다
break
(여전히 가능하지만 부도덕 한 해커가 시뮬레이션을위한 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);
}
}
위키 백과 항목 에서 위의 코드 .
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에 대해 아무것도 가지고 있지 않지만 언급 한 것처럼 루프에 사용하지 않는 몇 가지 이유를 생각할 수 있습니다.
- 범위를 제한하지 않으므로 내부에서 사용하는 임시 변수는 나중에까지 해제되지 않습니다.
- 범위를 제한하지 않으므로 버그가 발생할 수 있습니다.
- 범위를 제한하지 않으므로 나중에 동일한 범위의 코드에서 동일한 변수 이름을 다시 사용할 수 없습니다.
- 범위를 제한하지 않으므로 변수 선언을 건너 뛸 수 있습니다.
- 사람들은 그것에 익숙하지 않으며 코드를 읽기 어렵게 만듭니다.
- 이 유형의 중첩 루프는 스파게티 코드로 이어질 수 있으며 노멀 루프는 스파게티 코드로 이어지지 않습니다.
goto를 사용하기에 좋은 곳 중 하나는 여러 지점에서 중단 할 수있는 절차에 있으며, 각 지점에는 다양한 수준의 정리가 필요합니다. Gotophobes는 항상 구조화 된 코드와 일련의 테스트로 gotos를 대체 할 수 있지만 과도한 들여 쓰기를 제거하기 때문에 이것이 더 간단하다고 생각합니다.
if (! openDataFile ()) goto quit; if (! getDataFromFile ()) closeFileAndQuit로 이동합니다. if (! allocateSomeResources) 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;
}
다음은 좋은 goto의 예입니다.
// No Code
goto가 올바르게 사용되는 것을 보았지만 상황은 일반적으로 추악합니다. 그 goto
자체 의 사용 이 원본보다 훨씬 더 나쁠 때만 그렇습니다. @Johnathon 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
}
My gripe about this is that you lose block scoping; any local variables declared between the gotos remains in force if the loop is ever broken out of. (Maybe you're assuming the loop runs forever; I don't think that's what the original question writer was asking, though.)
The problem of scoping is more of an issue with C++, as some objects may be depending on their dtor being called at appropriate times.
For me, the best reason to use goto is during a multi-step initialization process where the it's vital that all inits are backed out of if one fails, a la:
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;
I don't use goto's myself, however I did work with a person once that would use them in specific cases. If I remember correctly, his rationale was around performance issues - he also had specific rules for how. Always in the same function, and the label was always BELOW the goto statement.
#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:
Why not do your example like this:
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
'Program Tip' 카테고리의 다른 글
Python : ISO-8859-1 / latin1에서 UTF-8로 변환 (0) | 2020.10.08 |
---|---|
아카이브시 "명령 / usr / sbin / chown이 종료 코드 1로 실패" (0) | 2020.10.08 |
Android GCM SENDER_ID, 어떻게받을 수 있나요? (0) | 2020.10.08 |
Bash에서 명령 출력을 숨기는 방법 (0) | 2020.10.08 |
Android-R은 변수로 해석 될 수 없습니다. (0) | 2020.10.08 |