C 또는 C++의 좋은 gotos 예
이 실에서 우리는 의 좋은 이용 사례들을 살펴본다.goto
C 또는 C++로 표시한다.그것은 사람들이 내가 농담하는 것이라고 생각했기 때문에 투표한 답변에서 영감을 받았다.
요약(레이블이 원래에서 의도를 더욱 명확하게 하기 위해 변경됨):
infinite_loop:
// code goes here
goto infinite_loop;
대안보다 더 나은 이유:
- 구체적이다.
goto
무조건적인 가지를 야기하는 언어 구성이다.대안은 항상 참된 상태로 퇴보하는 조건부 분기를 지지하는 구조물의 사용에 의존한다. - 라벨은 별도의 설명 없이 의도를 문서화한다.
- 판독기가 개입된 코드를 조기에 스캔할 필요가 없음
break
s (원칙 없는 해커가 시뮬레이션하는 것은 여전히 가능하지만)continue
일찍부터goto
).
규칙:
- 고토포비들이 이기지 못한 척 해.위와 같은 것은 확립된 관용어에 어긋나기 때문에 실제 코드로 사용할 수 없는 것으로 이해된다.
- 우리 모두가 '해롭다고 생각하는 고토'에 대해 들어봤다고 가정하고, 고토가 스파게티 코드를 쓰는 데 사용될 수 있다는 것을 알고 있다.
- 예를 들어 동의하지 않으면 기술적 장점만을 가지고 비판하라('사람들이 goto를 좋아하지 않기 때문에'는 기술적인 이유가 아니다).
어른들 처럼 이 얘기를 할 수 있는지 봅시다.
편집
이 문제는 이제 끝난 것 같다.그것은 몇 가지 고품질의 답을 만들어냈다.모두에게 고마워, 특히 내 작은 루프를 진지하게 본 사람들 말이야.대부분의 회의론자들은 블록 범위 부족에 대해 우려했다.@kinmars가 논평에서 지적했듯이, 당신은 언제나 루프 몸체에 브레이스를 둘 수 있다.나는 그것을 지나가는 것을 주목한다.for(;;)
그리고while(true)
치아 교정기를 공짜로 주지도 마라. (그리고 그것을 생략하는 것은 버그를 야기할 수도 있다.어쨌든, 나는 이 사소한 일로 너의 뇌력을 더 이상 낭비하지 않을 거야 - 나는 무해하고 관용적인 것으로 살 수 있어.for(;;)
그리고while(true)
(직장을 지키고 싶다면 그렇다.)
다른 응답들을 고려했을 때, 많은 사람들이goto
항상 다른 방식으로 다시 써야 하는 것 처럼요물론 당신은 a를 피할 수 있다.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 없이 중첩된 루프를 탈출할 수 있는 간단한 방법은 없다.
여기 (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
'IT이야기' 카테고리의 다른 글
Vue.js 2.0 모듈 빌드 실패:구문 오류:웹 팩, Elixir 및 꿀꺽을 사용한 예상치 못한 토큰 (0) | 2022.05.03 |
---|---|
변수 선언 이전과 루프 내 간의 차이? (0) | 2022.05.03 |
Java 동기화된 메서드 잠금 객체 또는 메서드? (0) | 2022.05.03 |
뷰피 테이블에서 상세 행 전환 (0) | 2022.05.03 |
vue 인스턴스의 websocket.onmessage 메서드를 호출하는 방법 (0) | 2022.05.03 |