do {…} while (false)


125

개인의 일부 코드를 살펴 보았는데 그의 기능에 패턴이있는 것 같습니다.

<return-type> function(<params>)
{
 <initialization>

 do
 {
   <main code for function>
 }
 while(false);

 <tidy-up & return>
}

나쁘지 않고 더 독특합니다 (실제 코드는 상당히 깔끔하고 놀랍지 않습니다). 그것은 내가 전에 본 것이 아니며 누군가 그 뒤에있는 논리를 생각할 수 있는지 궁금했습니다.


2
"일반"버전으로 변경하고 여전히 컴파일되는지 확인한 적이 있습니까? 정상적으로 작성되었을 때 컴파일에 실패하면 컴파일러 오류가 이것이 수행 된 이유에 대한 단서를 제공 할 수 있습니다.
Mark Byers

11
우리에게 그의 의도를 추측하는 것보다 "개인"에게 물어 보는 것은 어떨까요?

1
아마도 그의 교수는 a를 사용하도록 요구했고 그 do...while()이후로 그 코드를 함수 템플릿으로 사용했습니다.
Hogan

6
@Neil ... 나는 그와 마주 할 때 멍청 해 보이는 것을 피하고 싶다. 그는 내가 생각하지 못한 초 고급 C ++ 사용법을 설명한다.
Mr. Boy

6
이미 상당히 다른 답변이있는 것 같습니다. 원저자에게 그들의 의도가 무엇인지 물어보고 다시 게시 할 수 있습니까?
nevets1219

답변:


175

할 수 있습니다 break아웃 do{...}while(false).


95
+1은 아마도 코드의 의도 일 것이기 때문입니다.하지만 이와 같이하는 것은 바보처럼 위장한 고토 일뿐입니다. goto가 작업에 적합한 도구라고 생각한다면 # $ (* # @ goto를 사용해야합니다.
dsimcha

55
위장 된 고토 그 이상입니다. 제한된 (구조화 된) goto입니다.
Thomas Eding

19
어떤 방식으로 "제한"됩니까? 앞으로 점프하는 것만이 "제한"이 아닙니다. 고토 (goto)는 고토 (goto)이며, 하나가 아닌 것처럼 보이도록 옷을 입히는 것은 처음에 고토를 사용하는 것보다 더 나쁩니다.
아논.

44
@Anon .: 앞으로 점프하는 것은 goto에 대한 제한이며, 점프하는 것은 확실히 제한입니다. gotos의 진짜 문제는 스파게티 코드이며, 전방 및 아웃 점프가 크게 제한됩니다.
David Thornley

33
실제 루프는 의미 상 goto가 아닙니다. 조건부는 의미 상 goto가 아닙니다. "함수 끝으로 이동하여 정리 코드 수행" 의미 상 goto입니다. 의미론이 적용될 때 gotos를 사용하고, 무서워서 의미 상 다른 것을 차려 입지 마십시오.
아논.

126

많은 사람들이 "goto"를 쓰는 어색한 방법으로 break와 함께 자주 사용된다고 지적합니다. 함수에 직접 작성 되었다면 아마도 사실 일 것입니다.

매크로에서 OTOH do { something; } while (false)는 매크로 호출 후 세미콜론을 강제 하는 편리한 방법이며, 다른 토큰은 절대 따라 올 수 없습니다.

또 다른 가능성은 한 번 거기에 루프가 있었거나 미래에 반복이 추가 될 것으로 예상된다는 것입니다 (예 : 테스트 기반 개발에서는 테스트를 통과하는 데 반복이 필요하지 않았지만 논리적으로 다음과 같은 경우에 루프하는 것이 합리적 일 것입니다. 기능은 현재 필요한 것보다 다소 더 일반적이어야 함)


18
매크로에서 이것의 유용성을 언급하는 +1; 아무도 언급하지 않은 것에 놀랐습니다!
Nick Meyer

7
네, 매크로는 실제로 이것의 완벽하게 유효한 사용법입니다. 물론 외부 매크로는 어리석은 일입니다 ...;)
jalf

12
Scoped goto 이기 때문에 어색하지 않고 유용 합니다. do 루프에서 선언 한 모든 변수가 파괴되는 반면 goto는 그렇게하지 않습니다.
Ana Betts

9
@Paul : goto를 사용하여이 동작을 강제하기 위해 많은 문 주위에 중괄호를 추가하는 것을 방해하는 것은 없습니다.
erikkallen

5
@Paul : 블록 외부로 이동하면 break와 마찬가지로 C ++에서 지역 변수가 파괴됩니다. 그리고 C 변수는 실제로 파괴되지 않으며 스택 공간은 단순히 회수됩니다.
Ben Voigt

25

goto로서의 휴식이 아마도 답일 것입니다. 그러나 나는 다른 아이디어를 제시 할 것입니다.

아마도 그는 지역적으로 정의 된 변수를 갖고 싶었고이 구조를 사용하여 새로운 범위를 얻었습니다.

최근 C ++에서는 {...}어디에서나 허용되지만 항상 그런 것은 아닙니다.


30
이 경우 중괄호를 사용했을 수도 있습니다.
Nemanja Trifunovic

2
@Nemanja, 얼마나 많은 개발자가 그것을 모르고 Hogan이 제안하는 것과 관련된 것을 시도하는 것에 놀랄 것입니다
Polaris878

8
@Polaris @Nemanja, 4 년 동안 C / C ++로 프로그래밍 할 때까지는 {} 어디에서나 새로운 로컬 범위를 만들 수 있다는 것을 알게되었습니다 .. 이것은 switch-case코드 에서 특히 편리 합니다
Earlz

1
@Nemanja : 정확히 언제인지 모르겠지만 {...}어디에서나 C ++로 더 현대적인 개발이 이루어지고 있다고 확신합니다 (내가 사용한 첫 번째 C ++는 전처리기로 구현되었으며 현대적인 사용을 허용하지 않았습니다.) 저자는 아주 오래된 학교였습니다.
Hogan

2
언제 어디서나 중괄호를 허용하지 않았습니까? 나는 15 년 전에 프로그래밍을 시작했고 그때 허용되었다 (제 교과서와 내가 시도한 모든 컴파일러에서).
erikkallen

20

함수에 대한 잠재적 인 종료 점이 많을 때 유용한 패턴으로 사용되는 것을 보았지만 함수가 종료되는 방법에 관계없이 항상 동일한 정리 코드가 필요합니다.

종료 지점에 도달 할 때마다 중단하고 나중에 나머지 논리를 인라인으로 처리함으로써 귀찮은 if / else-if 트리를 훨씬 쉽게 읽을 수 있습니다.

이 패턴은 goto 문이없는 언어에서도 유용합니다. 아마도 원래 프로그래머가 패턴을 배운 곳일 것입니다.


15
그런 다음 얇게 위장한 고토 대신 정직하고 직접적인 고토를 사용하십시오.
dsimcha

4
나는이 방법이 더 좋다. 읽기 쉽고 고토의 오명을 가지고 있지 않습니다.
Cameron

8
gotos는 드물게 로컬로 사용하면 읽기가 매우 쉽습니다. 그들은 흐름 제어의 주요 형태 였고 수백 줄을 뛰어 넘을 때 뒤에서 낙인을 얻었습니다.
dsimcha

13
"오명"때문에 goto를 사용하지 않는 것은화물 컬트 프로그램의 확실한 신호입니다.
아논.

6
대량의 정리 코드가 나쁜 냄새라는 것은 말할 것도 없습니다. 이것은 C ++이므로 정리 코드는 일반적으로 RAII 처리 중에 호출되는 소멸자에 있어야합니다.
데이비드 손리

12

나는 그런 코드를 보았으므로 일종의 break것으로 사용할 수 있습니다 goto.


10

이것은 while의 의미를 얻기 위한 변태 일뿐 입니다.goto tidy-up goto라는 단어를 사용하지 않고 입니다.

외부 의 다른 루프 를 사용 하면 독자에게 모호해 지기 때문에 잘못된 형식 입니다. "이것이 출구로 가야하나요? 아니면 내부 루프를 벗어나기위한 것입니까?"whilebreaks


10

. break대신 작성하는 것이 더 편리하다고 생각합니다 goto end. 의도를 명확하게하는 레이블의 이름을 생각할 필요도 없습니다. 특정 이름을 가진 레이블로 이동하고 싶지는 않습니다. 여기서 나가고 싶어.

또한 어쨌든 중괄호가 필요할 가능성이 있습니다. 그래서 이것은 do{...}while(false);버전입니다 :

do {
   // code
   if (condition) break; // or continue
   // more code
} while(false);

그리고 이것이 사용하고 싶다면 표현해야 할 방법입니다 goto.

{
   // code
   if (condition) goto end;
   // more code
}
end:

첫 번째 버전의 의미를 이해하기 훨씬 쉽다고 생각합니다. 또한 작성하기 쉽고 확장하기 쉬우 며를 지원하지 않는 언어로 번역하기가 더 쉽습니다 goto.


의 사용에 대해 가장 자주 언급되는 우려 break는 심하게 위장 된 goto. 그러나 실제로 break는 다음과 더 유사합니다 return. 두 명령어 모두에 비해 거의 구조화 된 코드 블록에서 튀어 나옵니다 goto. 그럼에도 불구하고 두 명령어 모두 코드 블록에서 여러 개의 종료점을 허용하므로 때때로 혼란 스러울 수 있습니다. 결국 나는 특정 상황에서 가장 명확한 해결책을 찾으려고 노력할 것입니다.


아, 방금 대답하기 전에 질문을 완전히 이해하지 못했다는 것을 알았습니다. 나는 do{ ... }while(false);일반적으로 사용에 관한 것이라고 생각했습니다 . 그러나 실제로는 일종의 try{ ... }finally{ ... }.
Robert

goto보다는 break와 return 사이의 평행선을 잘 관찰했습니다. 가장 명확한 솔루션이 최고라는 데 동의하십시오. 대부분의 경우 break 대신 return을 사용하는 별도의 함수에서 이와 같은 코드를 캡슐화 한 다음 호출 함수에서 정리를 수행하는 것이 더 분명 할 것입니다.
persiflage

7

이 트릭은 goto코드에서 명시적인 것을 사용하기에는 너무 부끄러워하는 프로그래머가 사용 합니다. 위 코드의 작성자는 코드 중간에서 "정리 및 반환"지점으로 바로 이동할 수있는 기능을 원했습니다. 그러나 그들은 라벨과 명시적인 goto. 대신 break위의 "가짜"주기의 본문 내부 를 사용 하여 동일한 효과를 얻을 수 있습니다.


7

이것은 매우 일반적인 관행입니다. 에서 C . 나는 당신이 "나는 사용하지 않는다"는 방식 으로 자신 에게 거짓말을 하고 싶다고 생각하려고 노력한다 goto. 그것에 대해 생각하면,goto 비슷하게 사용 입니다. 사실 그것은 또한 들여 쓰기 수준을 감소시킬 것입니다.

하지만이 do..while루프가 자주 커지는 경향 이 있음을 알았습니다 . 그리고 그들은 내부에 ifs와 elses 를 가져 와서 코드를 테스트 할 수있는 것은 말할 것도없고 실제로는 읽기 어렵게 만듭니다.

그것들 do..while은 일반적으로 정리를 위한 것 입니다. 가능한 한 꼭 내가 사용하는 것을 선호 RAII를 하고 조기 반환 A로부터 짧은 기능. 반면에, C는 만큼 편의 시설로 당신을 제공하지 않는 C ++이 수행하는 만드는 do..while최고의 한 것은 정리를 할 접근한다.


6

C 프로그래머처럼 보입니다. C ++에서 자동 변수에는 정리에 사용하는 소멸자가 있으므로 반환 전에 정리할 필요가 없습니다. C에서는이 RAII 관용구 가 없었으므로 일반적인 정리 코드가있는 경우 goto이를 사용하거나 위와 같이 원스 스루 루프를 사용합니다.

C ++ 관용구에 비해 주요 단점은 본문에서 예외가 발생하면 정리되지 않는다는 것입니다. C에는 예외가 없었기 때문에 이것은 문제가되지 않았지만 C ++에서는 나쁜 습관이됩니다.


4

몇 가지 설명. 첫 번째는 일반적이고 두 번째는 매개 변수가있는 C 전 처리기 매크로에 고유합니다.

흐름 제어

나는 이것이 일반 C 코드에서 사용되는 것을 보았습니다. 기본적으로 goto의 안전한 버전입니다. 탈출 할 수 있고 모든 메모리가 제대로 정리되기 때문입니다.

goto같은 것이 좋은 이유는 무엇 입니까? 글쎄, 거의 모든 줄이 오류를 반환 할 수있는 코드가 있지만 모든 줄에 동일한 방식으로 반응해야하는 경우 (예 : 정리 후 호출자에게 오류를 전달하여) 일반적으로 if( error ) { /* cleanup and error string generation and return here */ }as 를 피하는 것이 더 읽기 쉽습니다. 정리 코드의 중복을 방지합니다.

그러나 C ++에서는 정확히 이러한 목적으로 예외 + RAII가 있으므로 잘못된 코딩 스타일로 간주합니다.

세미콜론 검사

함수와 같은 매크로 호출 후 세미콜론을 잊어 버리면 인수가 원하지 않는 방식으로 축소되어 유효한 구문으로 컴파일 될 수 있습니다. 매크로를 상상해보십시오

#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");

그것은 실수로 다음과 같이 불립니다.

if( foo )
    PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
    doSomethingElse();

는 "다른"은과 관련된 것으로 간주 될 gDebugModeOn때, foo이다 false의 정확한 일어날 의도 무슨 역.

임시 변수에 대한 범위 제공.

do / while에는 중괄호가 있으므로 임시 변수에는 이스케이프 할 수없는 명확하게 정의 된 범위가 있습니다.

"원치 않는 세미콜론"경고 방지

일부 매크로는 디버그 빌드에서만 활성화됩니다. 다음과 같이 정의합니다.

#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n) 
#endif

이제 조건부 내 릴리스 빌드에서 이것을 사용하면 다음과 같이 컴파일됩니다.

if( foo )
    ;

많은 컴파일러는 이것을 다음과 같은 것으로 간주합니다.

if( foo );

종종 실수로 작성됩니다. 그래서 당신은 경고를받습니다. 가 할 {} (거짓)은 컴파일러에서이 숨 깁니다, 그리고 당신이 있다는 표시로 인정되는 동안 정말 여기에 아무것도하지 않고 싶다.

조건문에 의한 줄 캡처 방지

이전 예의 매크로 :

if( foo )
    DBG_PRINT_NUM(42)
doSomething();

이제 디버그 빌드에서 우리는 습관적으로 세미콜론을 포함했기 때문에 잘 컴파일됩니다. 그러나 릴리스 빌드에서는 갑자기 다음과 같이 바뀝니다.

if( foo )

doSomething();

또는 더 명확한 형식

if( foo )
    doSomething();

의도 한 것이 전혀 아닙니다. 매크로 주위에 do {...} while (false)를 추가하면 누락 된 세미콜론이 컴파일 오류로 바뀝니다.

OP에 대한 의미는 무엇입니까?

일반적으로 오류 처리를 위해 C ++에서 예외를 사용하고 매크로 대신 템플릿을 사용하려고합니다. 그러나 매크로가 여전히 필요하거나 (예 : 토큰 붙여 넣기를 사용하여 클래스 이름을 생성 할 때) 매우 드문 경우 또는 일반 C로 제한되는 경우 이것은 유용한 패턴입니다.


범위 지정과 관련하여 루프 장치가 필요하지 않습니다. "미 장식"블록은 합법적입니다 : x =1; y = 2; { int tmp = y; y = x; x = tmp; }.
chepner

장식되지 않은 블록은 불필요한 부작용을 일으킬 수있는 누락 된 세미콜론의 존재를 강제하지 않습니다. Do {} while (); 세미콜론이 필요하므로 위의 예제와 같이 매크로가 릴리스 빌드에서 아무것도 정의하지 않는 경우 다음 명령문이 "if"로 그려지지 않습니다.
uliwitness

단순히 매크로에 대한 더 나은 정의를 제공함으로써 피할 수 없습니까? #define DBG_PRINT_NUM(n) {}.
chepner

1
아니요, {}는 전체 문이므로 ";"과 동일합니다. 따라서 작성하면 if(a) DBG_PRINT_NUM(n); else other();컴파일되지 않습니다. if(a) {} else other();또는 만 if(a) ; else other();유효하지만 유효 if(a) {}; else other();하지 않습니다. "if"절이 두 개의 문으로 구성되기 때문입니다.
uliwitness

2

즉, 그래서 어쩌면이 사용되는 break어느 시점에서 더 코드의 실행을 중지하는 데 사용되는 내부 될 수 있습니다 :

do {
    if (!condition1) break;
    some_code;
    if (!condition2) break;
    some_further_code;
    // …
} while(false);

7
그렇게하는 goto것은 누군가가 "나쁘다"고 들었 기 때문에 사용을 피하려는 시도처럼 보입니다 .
아논.

1
아마도 C ++에는 바로 이러한 이유로 예외가 있습니다.
TED

2

나는 이것이 break또는 continue진술 을 사용하기 위해 수행되었다고 생각 합니다. 일종의 "goto"코드 로직.


2

간단 break합니다. 문을 사용하여 언제든지 가짜 루프에서 벗어날 수 있습니다 . 또한 do블록은 별도의 범위입니다 ( { ... }만으로도 달성 할 수 있음).

이러한 상황에서는 RAII (기능이 종료되면 객체가 자동으로 올바르게 소멸됨)를 사용하는 것이 더 좋습니다. 또 다른 유사한 구조를 사용하는 것입니다 goto- 그래, 내가 아는 그것의 악 , 그러나과 같이 일반적인 정리 코드를 사용할 수 있습니다 :

<return-type> function(<params>)
{
 <initialization>

 <main code for function using "goto error;" if something goes wrong>

 <tidy-up in success case & return>

 error:

 <commmon tidy-up actions for error case & return error code or throw exception>
}

(제쳐두고 : do-while-false 구문은 누락 된 continue진술을 찾기 위해 Lua에서 사용됩니다 .)


2

많은 답변자들이 do{(...)break;}while(false). 또 다른 실제 사례로 그림을 보완하고 싶습니다.

다음 코드에서는 포인터가 operation가리키는 주소를 기반으로 열거자를 설정 해야했습니다 data. switch-case는 먼저 스칼라 유형에서만 사용할 수 있기 때문에 이렇게 비효율적으로 수행했습니다.

if (data == &array[o1])
    operation = O1;
else if (data == &array[o2])
    operation = O2;
else if (data == &array[on])
    operation = ON;

Log("operation:",operation);

그러나 Log () 및 나머지 코드가 선택한 작업 값에 대해 반복되므로 주소가 이미 발견되었을 때 나머지 비교를 건너 뛰는 방법을 헤매고있었습니다. 그리고 이것은 do{(...)break;}while(false)편리한 곳입니다.

do {
    if (data == &array[o1]) {
        operation = O1;
        break;
    }
    if (data == &array[o2]) {
        operation = O2;
        break;
    }
    if (data == &array[on]) {
        operation = ON;
        break;
    }
} while (false);

Log("operation:",operation);

다음과 같은 진술 break에서 왜 그가 똑같이 할 수 없었는지 궁금 할 if것입니다.

if (data == &array[o1])
{
    operation = O1;
    break;
}
else if (...)

break, 또는 유형 이든 가장 가까운 둘러싸는 루프 또는 스위치 와 만 상호 작용 하므로 불행히도 작동하지 않습니다.forwhiledo .. while


1

저자는 몇 살입니까?

80 년대 후반에이를 수행 한 실시간 포트란 코드를 발견했기 때문에 묻습니다. 스레드가없는 OS에서 스레드를 시뮬레이션 할 수있는 정말 좋은 방법입니다. 전체 프로그램 (스케줄러)을 루프에 넣고 "스레드"루틴을 하나씩 호출합니다. 스레드 루틴 자체는 여러 조건 중 하나가 발생할 때까지 반복되는 루프입니다 (종종 하나는 일정량의 시간이 지났습니다.) 이것은 "협동 멀티 태스킹"입니다. 개별 스레드가 CPU를 포기하고 다른 스레드가 굶주 리지 않도록하는 것은 스레드 우선 순위를 시뮬레이션하기 위해 루프 서브 프로그램 호출을 중첩 할 수 있습니다. 밴드.



0

나는 얇게 위장한 고토로서의 사용법에 대한 대부분의 포스터에 동의합니다. 매크로는 또한 스타일로 코드를 작성하는 잠재적 동기로 언급되었습니다.

나는 또한이 구조가 C / C ++ 혼합 환경에서 가난한 사람의 예외로 사용되는 것을 보았다. "중단"이있는 "do {} while (false)"은 일반적으로 루프에서 예외가 발생하는 경우 코드 블록의 끝으로 건너 뛰는 데 사용할 수 있습니다.

나는 또한 "기능 당 단일 수익"이데올로기가 시행되는 상점에서 사용되는이 구조를 감지했습니다. 다시 말하지만, 이것은 명시적인 "goto"를 대신합니다. 그러나 동기는 코드를 "건너 뛰기"하고 해당 함수 내에서 실제 실행을 계속하는 것이 아니라 여러 반환 지점을 피하는 것입니다.


0

저는 Adobe InDesign SDK로 작업하며 InDesign SDK 예제에는 이와 같이 작성된 거의 모든 기능이 있습니다. 기능이 일반적으로 정말 길다는 사실 때문입니다. 응용 프로그램 개체 모델에서 무엇이든 가져 오기 위해 QueryInterface (...)를 수행해야하는 곳. 따라서 일반적으로 모든 QueryInterface 뒤에는 if잘 진행되지 않습니다.


0

많은 사람들이 이미이 구조와 a 사이의 유사성을 언급 goto했으며 goto에 대한 선호도를 표현했습니다. 아마도이 사람의 배경에는 코딩 지침에 의해 goto가 엄격하게 금지 된 환경이 포함되어 있습니까?


0

제가 생각할 수있는 또 다른 이유 는 중괄호를 장식 하는 반면, 최신 C ++ 표준 네이 키드 중괄호는 괜찮지 않다고 생각합니다 (ISO C는이를 좋아하지 않습니다). 그렇지 않으면 보푸라기와 같은 정적 분석기를 조용히합니다.

왜 그것들을 원하는지, 아마도 가변 범위 또는 디버거의 이점을 확신하지 못합니다.

Trivial Do While loopBraces are Good from C2를 참조하십시오 .

내 용어를 명확히하려면 (표준 사용법을 따른다고 생각합니다) :

알몸 교정기 :

init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();

빈 중괄호 (NOP) :

{}

예 :

while (1)
   {}  /* Do nothing, endless loop */

블록 :

if (finished)
{
     closewindows(&windows);
     freememory(&cache);
}

어느 것이 될 것인가

if (finished)
     closewindows(&windows);
freememory(&cache);

중괄호가 제거되면 지역 변수의 범위뿐만 아니라 실행 흐름이 변경됩니다. 따라서 '자립'이나 '알몸'이 아닙니다.

네이 키드 중괄호 또는 블록을 사용하여 표시하려는 (인라인) 함수에 대한 잠재적 인 코드 섹션을 나타낼 수 있지만 그 당시에는 리팩터링하지 않을 수 있습니다.


정말? 부끄러운 일입니다. C에 대해 내가 좋아하는 몇 가지 사항 중 하나는 거의 모든 곳에서 새 중첩 범위를 선언 할 수 있다는 점입니다.
TED

1
알몸 중괄호는 가끔 이상한 충돌을 해결하는 데 도움이됩니다. blogs.msdn.com/oldnewthing/archive/2004/05/20/135841.aspx를 참조하십시오 .
Brian

1
C ++에서 블록 (즉, "naked braces")은 단일 문이 허용되는 곳이면 어디에서나 사용할 수 있습니다.
Ben Voigt

@BenVoigt 빈 중괄호 즉, NOP는 선형 명령 시퀀스 주위에 추가 된 블록 인 "네이 키드 중괄호"와 다릅니다. 예 :`printf ( "Hello"); {putchar ( ','); putchar (0x20); } printf ( "world! \ n");`여기서 중괄호는 루프 또는 분기 제어의 일부 가 아닙니다 .
mctylr

@mctylr : 빈 중괄호에 대해 이야기 한 것이 아닙니다.
Ben Voigt

0

GOTO이 두 가지가 거의 동일 하기 때문에 a를 에뮬레이션하는 인위적인 방법입니다 .

// NOTE: This is discouraged!
do {
    if (someCondition) break;
    // some code be here
} while (false);
// more code be here

과:

// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here

반면에이 두 가지 모두 ifs 로 수행해야합니다 .

if (!someCondition) {
    // some code be here
}
// more code be here

포워드 GOTO의 긴 문자열 을 중첩 된 ifs 로 바꾸면 중첩이 약간 추악해질 수 있습니다 . 진정한 대답은 구식 언어 구조를 모방하지 않는 적절한 리팩토링입니다.

GOTOs가 포함 된 알고리즘을 필사적으로 음역하려고했다면 이 관용구로 할 수있을 것입니다. 그것은 확실히 비표준이며 언어의 예상되는 관용구에 가깝게 고수하지 않고 있다는 좋은 지표입니다.

나는 do / while이 실제로 어떤 것에 대한 관용적 해결책 인 C와 같은 언어를 알지 못합니다.

더 관용적이고 훨씬 더 읽기 쉽게 전체 엉망을 더 합리적인 것으로 리팩토링 할 수 있습니다.


1
Alan do..while(false)은 "정의되지 않은"횟수를 실행하기위한 것이 아니라 한 번 실행하기위한 것입니다 .
Dmitry

2
continue내가 보여준 것처럼 끝에 조건문이 있으면 정의되지 않은 횟수로 실행 됩니다. 하여 undefined나는 단순히 당신이 더 당신이 조건이 특정 반복에서 만난할지 여부를 예측할 수없는 한 번 이상 실행의 여부를 알 수없는 것을 의미한다. continues가 없으면 do..while(false)한 번 실행되지만 breaks가 없는 경우도 while(true)영원히 실행되므로 "기본 동작"은 루프로 수행 할 수 있는 작업 을 이해하는 데 실제로 관련이 없습니다 .
Alan Plum

여러 문이있는 매크로를 정의 할 때 유용합니다. do / while (false)로 래핑하면 다른 함수 호출처럼 if / else 문에서 매크로를 사용할 수 있습니다. 설명 은 noveltheory.com/TechPapers/while.htm 을 참조하십시오.
John Paquin

5
누군가의 의미를 이해하지 못합니다 continue. continue루프를 반복하지 않습니다. 는 " continue문은에서만 발생한다 반복 문 및 원인 작은 바깥의 루프 연속 부에 전달하는 제어 반복 문 루프의 끝 부분이다."
Ben Voigt

-1, @BenVoigt가 지적한 이유로 상위 두 문장은 동일하지 않습니다.
cmh

0

일부 코더는 기능에서 단 하나의 종료 / 복귀를 선호합니다. 더미의 사용 do {....} while (false); 작업을 마치면 더미 루프를 "탈출"할 수 있으며 여전히 한 번의 반환이 있습니다.

저는 자바 코더이므로 제 예는 다음과 같습니다.

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class p45
{
    static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
    static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());

    public static  void main(String[] argv)
    {
        for (int i = 0; i < 4; i++)
        {
            System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
        }
    }


    static String describeCake(int typeOfCake)
    {
        String result = "unknown";
        do {
            // ensure type of cake is valid
            if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;

            if (forbidden.contains(typeOfCake)) {
                result = "not for you!!";
                break;
            }

            result = cakeNames.get(typeOfCake);
        } while (false);
        return result;
    }
}


-1

이것은 재미 있습니다. 다른 사람들이 말했듯이 루프 내부에는 아마도 중단이있을 것입니다. 나는 이렇게했을 것이다.

while(true)
{
   <main code for function>
   break; // at the end.
}

2
영원히 반복 될 가능성이 있습니까? do..while(false)항상 출구 while(true)는 더 위험한 편입니다.
Dmitry

1
while(true)대부분의 언어에서 올바른 관용구입니다. GUI 응용 프로그램에서 프로그램의 메인 루프로 종종 찾을 수 있습니다. 기본적으로 프로그램이 그렇게하라는 지시가있을 때까지 죽지 말아야한다고 가정하고 있기 때문에 a do..while(false)는 모든 종류의 인위적인 논리를 유발합니다. 이 접근 방식은 완벽 주의적 관점에서 더 위험 할 수 있지만 의미 상 더 쉽고 인간 프로그래머 (Skynet)에게 오류가 발생하기 쉽습니다.
Alan Plum

2
@dmitry은 do{...}while(false)정확히 동일합니다while(true){ .. break;}
N 1.1

4
@ N1.1 : 존재 continue하지 않고 동일하지 않습니다.
Ben Voigt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.