"do {…} while ()"루프가 필요합니까?
Bjarne Stroustrup (C ++ 작성자)은 "do / while"루프를 피하고 대신 "while"루프로 코드를 작성하는 것을 선호한다고 말했습니다. [아래 인용문 참조]
이것을 듣고 나는 이것이 사실임을 알게되었습니다. 당신의 생각은 무엇입니까? 대신 "while"을 사용하는 것보다 "do / while"이 훨씬 명확하고 이해하기 쉬운 예가 있습니까?
일부 답변에 대한 답변 : 예, "do / while"과 "while"의 기술적 차이를 이해합니다. 이것은 가독성과 루프를 포함하는 코드 구조화에 대한 더 깊은 질문입니다.
다른 방법으로 물어 보겠습니다. "do / while"을 사용하는 것이 금지되어 있다고 가정합니다. 이것이 "while"을 사용하여 부정확 한 코드를 작성하는 것 외에는 선택의 여지가없는 현실적인 예가 있습니까?
"C ++ 프로그래밍 언어", 6.3.3에서 :
제 경험상 do-statement는 오류와 혼란의 원인입니다. 그 이유는 조건이 평가되기 전에 본문이 항상 한 번 실행되기 때문입니다. 그러나 신체가 제대로 작동하려면 처음에도 상태와 매우 유사한 것이 유지되어야합니다. 내가 생각했던 것보다 더 자주 나는 프로그램이 처음 작성되고 테스트되었을 때나 나중에 이전 코드가 수정 된 후에 예상대로 유지되지 않는 조건을 발견했습니다. 나는 또한 "내가 볼 수있는 전방"조건을 선호한다. 결과적으로 나는 do-statements를 피하는 경향이 있습니다. -비얀
예, do while 루프를 while 루프로 다시 작성할 수 있다는 데 동의하지만 항상 while 루프를 사용하는 것이 더 낫다는 데 동의하지 않습니다. 항상 한 번 이상 실행되는 동안 수행하면 매우 유용한 속성입니다 (가장 일반적인 예는 키보드에서 입력 확인).
#include <stdio.h>
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
물론 이것은 while 루프로 다시 작성할 수 있지만 일반적으로 훨씬 더 우아한 솔루션으로 간주됩니다.
do-while은 사후 조건이있는 루프입니다. 루프 본문을 한 번 이상 실행해야하는 경우에 필요합니다. 이것은 루프 조건을 현명하게 평가하기 전에 몇 가지 조치가 필요한 코드에 필요합니다. while 루프를 사용하면 두 사이트에서 초기화 코드를 호출해야하며 do-while을 사용하면 한 사이트에서만 호출 할 수 있습니다.
또 다른 예는 첫 번째 반복이 시작될 때 유효한 객체가 이미 있으므로 첫 번째 반복이 시작되기 전에 아무 것도 실행 (루프 조건 평가 포함)하고 싶지 않은 경우입니다. FindFirstFile / FindNextFile Win32 함수를 사용하는 예가 있습니다. 오류를 반환하거나 첫 번째 파일에 대한 검색 핸들을 반환하는 FindFirstFile을 호출 한 다음 오류가 반환 될 때까지 FindNextFile을 호출합니다.
의사 코드 :
Handle handle;
Params params;
if( ( handle = FindFirstFile( params ) ) != Error ) {
do {
process( params ); //process found file
} while( ( handle = FindNextFile( params ) ) != Error ) );
}
do { ... } while (0) 매크로가 잘 작동하도록 만드는 데 중요한 구조입니다.
실제 코드에서 중요하지 않더라도 (반드시 동의하지는 않음) 전 처리기의 일부 결함을 수정하는 데 중요합니다.
편집 : 오늘 내 코드에서 do / while이 훨씬 더 깨끗한 상황에 직면했습니다. 나는 쌍을 이루는 LL / SC 명령어 의 크로스 플랫폼 추상화를 만들고 있었다 . 다음과 같이 루프에서 사용해야합니다.
do
{
oldvalue = LL (address);
newvalue = oldvalue + 1;
} while (!SC (address, newvalue, oldvalue));
(전문가들은 SC 구현에서 oldvalue가 사용되지 않는다는 것을 알 수 있지만이 추상화가 CAS로 에뮬레이션 될 수 있도록 포함되어 있습니다.)
LL 및 SC는 do / while이 동등한 while 형식보다 훨씬 더 깨끗한 상황의 훌륭한 예입니다.
oldvalue = LL (address);
newvalue = oldvalue + 1;
while (!SC (address, newvalue, oldvalue))
{
oldvalue = LL (address);
newvalue = oldvalue + 1;
}
이런 이유로 Google Go가 do-while 구문을 제거하기로 결정 했다는 사실에 매우 실망합니다 .
조건이 충족 될 때까지 무언가를 "실행"하려는 경우에 유용합니다.
다음과 같이 while 루프에서 퍼지 될 수 있습니다.
while(true)
{
// .... code .....
if(condition_satisfied)
break;
}
(두 가지의 차이점을 알고 있다고 가정)
Do / While은 조건이 확인되고 while 루프가 실행되기 전에 코드를 부트 스트랩 / 사전 초기화하는 데 좋습니다.
코딩 규칙에서
- 만약 / while / ... 조건 에 부작용이없고
- 변수는 초기화되어야합니다.
그래서 우리는 거의 한 번도 없었습니다 do {} while(xx).
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
다음에서 다시 작성됩니다.
int main() {
char c(0);
while (c < '0' || c > '9'); {
printf("enter a number");
scanf("%c", &c);
}
}
과
Handle handle;
Params params;
if( ( handle = FindFirstFile( params ) ) != Error ) {
do {
process( params ); //process found file
} while( ( handle = FindNextFile( params ) ) != Error ) );
}
다음에서 다시 작성됩니다.
Params params(xxx);
Handle handle = FindFirstFile( params );
while( handle!=Error ) {
process( params ); //process found file
handle = FindNextFile( params );
}
다음과 같은 일반적인 관용구는 나에게 매우 간단 해 보입니다.
do {
preliminary_work();
value = get_value();
} while (not_valid(value));
피해야 할 재 작성은 다음과 do같습니다.
value = make_invalid_value();
while (not_valid(value)) {
preliminary_work();
value = get_value();
}
첫 번째 줄은 테스트 가 처음에 항상 참으로 평가 되는지 확인하는 데 사용됩니다 . 즉, 테스트는 항상 처음에는 불필요합니다. 이 불필요한 테스트가 없다면 초기 할당을 생략 할 수도 있습니다. 이 코드는 스스로 싸운다는 인상을줍니다.
이와 같은 경우 do구조는 매우 유용한 옵션입니다.
가독성 에 관한 것 입니다.
가독성이 높은 코드는 코드 유지 관리의 골칫거리를 줄이고 협업을 향상시킵니다.
대부분의 경우 다른 고려 사항 (예 : 최적화)은 훨씬 덜 중요합니다.
여기에 주석이 있으므로 자세히 설명하겠습니다. 를 사용
하는 코드 스 니펫 Ado { ... } while() 가 있고 while() {...}이에 상응하는 B 보다 더 읽기 쉬운 경우 A에 투표합니다 . 만약 당신이 B 를 선호한다면 , 루프 조건이 "앞으로"보이기 때문에 그것이 더 읽기 쉽다고 생각한다면 (따라서 유지 관리가 가능합니다.) 바로 진행하십시오 . B를 사용하십시오 .
내 요점은 : 당신의 눈 (그리고 당신의 동료들)에게 더 읽기 쉬운 코드를 사용하는 것입니다. 물론 선택은 주관적입니다.
제 생각에는 개인적인 선택 일뿐입니다.
대부분의 경우 do ... while 루프를 while 루프로 다시 작성하는 방법을 찾을 수 있습니다. 항상 그런 것은 아닙니다. 또한 때때로 컨텍스트에 맞게 do while 루프를 작성하는 것이 더 논리적 일 수 있습니다.
위를 보면 TimW의 답변이 그 자체로 말합니다. 핸들이있는 두 번째 것은 특히 내 의견으로는 더 지저분합니다.
이것은 내가 본 do-while에 대한 가장 깨끗한 대안입니다. do-while 루프가없는 Python에 권장되는 관용구입니다.
한 가지주의 할 점은 중단 조건을 뛰어 넘기 때문에 continuein을 가질 수 없다는 <setup code>것입니다. 그러나 do-while의 이점을 보여주는 예는 조건 전에 계속할 필요가 없습니다.
while (true) {
<setup code>
if (!condition) break;
<loop body>
}
여기서는 위의 do-while 루프의 가장 좋은 예 중 일부에 적용됩니다.
while (true); {
printf("enter a number");
scanf("%c", &c);
if (!(c < '0' || c > '9')) break;
}
이 다음 예는 //get data일반적으로 짧지 만 //process data부분이 길 수 있기 때문에 조건이 상단 근처에 유지되기 때문에 구조가 do-while보다 더 읽기 쉬운 경우 입니다.
while (true); {
// get data
if (data == null) break;
// process data
// process it some more
// have a lot of cases etc.
// wow, we're almost done.
// oops, just one more thing.
}
나는 단순히 다음과 같은 이유로 거의 사용하지 않습니다.
루프가 사후 조건을 확인하더라도 사후 조건을 처리하지 않도록 루프 내에서이 사후 조건을 확인해야합니다.
샘플 의사 코드를 가져옵니다.
do {
// get data
// process data
} while (data != null);
이론적으로는 간단 해 보이지만 실제 상황에서는 다음과 같이 보일 것입니다.
do {
// get data
if (data != null) {
// process data
}
} while (data != null);
추가 "if"확인은 IMO의 가치가 없습니다. while 루프 대신 do-while을 수행하는 것이 더 간결한 경우를 거의 발견하지 못했습니다. YMMV.
Dan Olson의 답변에 대한 unknown (google)의 질문 / 의견에 대한 응답 :
"do {...} while (0)은 매크로가 잘 작동하도록 만드는 중요한 구조입니다."
#define M do { doOneThing(); doAnother(); } while (0)
...
if (query) M;
...
없이 무슨 일이 일어나는지 봅 do { ... } while(0)니까? 항상 doAnother ()를 실행합니다.
구조화 된 프로그램 정리를 읽으십시오 . do {} while ()은 항상 while () do {}로 다시 작성할 수 있습니다. 시퀀스, 선택 및 반복은 이제까지 필요한 모든 것입니다.
루프 본문에 포함 된 것은 무엇이든 항상 루틴으로 캡슐화 할 수 있으므로 while () do {}를 사용해야하는 더러움은 다음보다 더 나빠질 필요가 없습니다.
LoopBody()
while(cond) {
LoopBody()
}
do-while 루프는 항상 while 루프로 다시 작성할 수 있습니다.
while 루프 만 사용할지, while, do-while 및 for-loops (또는 이들의 조합)를 사용할지 여부는 작업중인 프로젝트의 미학과 관례에 대한 취향에 따라 크게 달라집니다.
개인적으로, 루프 불변 IMHO에 대한 추론을 단순화하기 때문에 while 루프를 선호합니다.
do-while 루프가 필요한 상황이 있는지 여부 : 대신
do
{
loopBody();
} while (condition());
당신은 항상 할 수 있습니다
loopBody();
while(condition())
{
loopBody();
}
따라서 아니요, 어떤 이유로 할 수없는 경우 do-while을 사용할 필요가 없습니다. (물론이 예제는 DRY를 위반하지만 개념 증명 일뿐입니다. 제 경험상 일반적으로 do-while 루프를 while 루프로 변환하고 구체적인 사용 사례에서 DRY를 위반하지 않는 방법이 있습니다.)
"로마에있을 때 로마인처럼하십시오."
BTW : 당신이 찾고있는 인용구는 아마도 다음과 같을 것입니다 ([1], 섹션 6.3.3의 마지막 단락) :
From my experience, the do-statement is a source of error and confusion. The reason is that its body is always executed once before the condition is tested. For the correct functioning of the body, however, a similar condition to the final condition has to hold in the first run. More often than I expected I have found these conditions not to be true. This was the case both when I wrote the program in question from scratch and then tested it as well as after a change of the code. Additionally, I prefer the condition "up-front, where I can see it". I therefore tend to avoid do-statements.
(Note: This is my translation of the German edition. If you happen to own the English edition, feel free to edit the quote to match his original wording. Unfortunately, Addison-Wesley hates Google.)
[1] B. Stroustrup: The C++ programming language. 3rd Edition. Addison-Wessley, Reading, 1997.
First of all, I do agree that do-while is less readable than while.
But I'm amazed that after so many answers, nobody has considered why do-while even exists in the language. The reason is efficiency.
Lets say we have a do-while loop with N condition checks, where the outcome of the condition depends on the loop body. Then if we replace it with a while loop, we get N+1 condition checks instead, where the extra check is pointless. That's no big deal if the loop condition only contains a check of an integer value, but lets say that we have
something_t* x = NULL;
while( very_slowly_check_if_something_is_done(x) )
{
set_something(x);
}
Then the function call in first lap of the loop is redundant: we already know that x isn't set to anything yet. So why execute some pointless overhead code?
I often use do-while for this very purpose when coding realtime embedded systems, where the code inside the condition is relatively slow (checking the response from some slow hardware peripheral).
consider something like this:
int SumOfString(char* s)
{
int res = 0;
do
{
res += *s;
++s;
} while (*s != '\0');
}
It so happens that '\0' is 0, but I hope you get the point.
My problem with do/while is strictly with its implementation in C. Due to the reuse of the while keyword, it often trips people up because it looks like a mistake.
If while had been reserved for only while loops and do/while had been changed into do/until or repeat/until, I don't think the loop (which is certainly handy and the "right" way to code some loops) would cause so much trouble.
I've ranted before about this in regards to JavaScript, which also inherited this sorry choice from C.
Well maybe this goes back a few steps, but in the case of
do
{
output("enter a number");
int x = getInput();
//do stuff with input
}while(x != 0);
It would be possible, though not necessarily readable to use
int x;
while(x = getInput())
{
//do stuff with input
}
Now if you wanted to use a number other than 0 to quit the loop
while((x = getInput()) != 4)
{
//do stuff with input
}
But again, there is a loss in readability, not to mention it's considered bad practice to utilize an assignment statement inside a conditional, I just wanted to point out that there are more compact ways of doing it than assigning a "reserved" value to indicate to the loop that it is the initial run through.
I like David Božjak's example. To play devil's advocate, however, I feel that you can always factor out the code that you want to run at least once into a separate function, achieving perhaps the most readable solution. For example:
int main() {
char c;
do {
printf("enter a number");
scanf("%c", &c);
} while (c < '0' || c > '9');
}
could become this:
int main() {
char c = askForCharacter();
while (c < '0' || c > '9') {
c = askForCharacter();
}
}
char askForCharacter() {
char c;
printf("enter a number");
scanf("%c", &c);
return c;
}
(pardon any incorrect syntax; I'm not a C programmer)
참고URL : https://stackoverflow.com/questions/994905/is-there-ever-a-need-for-a-do-while-loop
'Program Club' 카테고리의 다른 글
| winforms 텍스트 상자에 검은 색 점 (•)이 표시되는 passwordchar는 무엇입니까? (0) | 2020.11.09 |
|---|---|
| Spring / Java 오류 : 네임 스페이스 요소 'annotation-config'… JDK 1.5 이상 (0) | 2020.11.09 |
| 이미지를 늘리지 않고 이미지의 너비와 높이를 설정하는 방법은 무엇입니까? (0) | 2020.11.09 |
| CSS : 표 열 사이의 테두리 만 (0) | 2020.11.09 |
| 소스 제어의 저장 프로 시저 / DB 스키마 (0) | 2020.11.08 |