Do-while 루프
1. 개요
do-while 루프는 프로그래밍 언어에서 사용되는 반복 제어 구조의 한 종류이다. 코드 블록을 먼저 실행한 후 조건을 평가하여, 조건이 참인 동안 코드 블록을 반복 실행한다. do-while 루프는 break 문을 사용하여 종료할 수 있으며, C/C++에서는 매크로 정의에 유용하게 사용된다. 다양한 프로그래밍 언어에서 do-while 루프 또는 유사한 기능을 제공하며, 팩토리얼 계산과 같은 예제를 통해 활용법을 확인할 수 있다.
| 설명 | 특정 조건이 참이 될 때까지 코드 블록을 반복적으로 실행하는 제어 흐름 문이다. |
|---|---|
| 종류 | 선 검사 루프: while 루프 후 검사 루프: do-while 루프 |
| do 블록 실행 | 먼저 do 블록 안의 코드를 실행한다. |
|---|---|
| 조건 검사 | while 문의 조건식을 평가한다. |
| 조건이 참인 경우 | 조건이 참이면 do 블록을 다시 실행한다. |
| 조건이 거짓인 경우 | 조건이 거짓이면 루프를 종료하고 다음 코드를 실행한다. |
| 최소 실행 횟수 | do 블록은 최소 한 번은 실행된다. |
|---|---|
| 조건 검사 시점 | 루프의 마지막에 조건을 검사한다. |
| 기본적인 do-while 루프 | | std::cout << i << std::endl; |
|---|---|
| 사용자 입력 검증 | | std::cout << "양수를 입력하세요: "; | std::cin >> number; |
| 메뉴 선택 | | std::cout << "메뉴:" << std::endl; | std::cout << "1. 항목 1" << std::endl; | std::cout << "2. 항목 2" << std::endl; | std::cout << "0. 종료" << std::endl; | std::cout << "선택: "; | std::cin >> choice; |
| 무한 루프 | 조건이 항상 참이면 무한 루프에 빠질 수 있으므로 주의해야 한다. |
|---|---|
| 세미콜론 | while 문 뒤에 반드시 세미콜론(;)을 붙여야 한다. |
| C 언어 | C 언어에서도 동일한 do-while 문을 사용할 수 있다. |
|---|---|
| C++ 언어 | C++ 언어에서도 동일한 do-while 문을 사용할 수 있다. |
| Java | Java에서도 동일한 do-while 문을 사용할 수 있다. |
| 구문 | |
|---|---|
| 의미 | 처리를 실행한 후, 조건식이 참인 동안 처리를 반복한다. 조건식이 거짓이 되면 do-while 문을 종료한다. |
| 특징 | 조건식의 평가가 처리가 실행된 후에 이루어지므로, 처리는 반드시 한 번 이상 실행된다. |
| 주의점 | while() 뒤에 반드시 세미콜론(;)을 붙인다. |
| 설명 | 조건이 충족될 때까지 코드 블록을 반복적으로 실행하는 제어 흐름 구조이다. "Post-test loop"라고도 한다. |
|---|---|
| 특징 | 루프 본문이 최소 한 번은 실행된다. 조건은 루프 본문 실행 후에 평가된다. |
-
제어 흐름 -
프로그램 카운터
프로그램 카운터는 CPU 내에서 다음에 실행될 명령어의 주소를 저장하는 레지스터로, 명령어 사이클의 fetch 단계에서 사용되어 명령어를 가져오고 실행 후 갱신되며, CPU 성능 향상 기술과 현대 프로그래밍 모델에 영향을 미친다. -
제어 흐름 -
예외 처리
예외 처리는 프로그램 실행 중 예외 발생 시 정상적인 실행 흐름을 유지하거나 안전하게 종료하기 위한 메커니즘으로, 많은 프로그래밍 언어에서 제공하며 예외 안전성을 목표로 한다. -
프로그래밍 구성체 -
형 변환
형 변환은 프로그래밍에서 변수의 데이터 타입을 변경하는 것으로, 암시적 형 변환과 명시적 형 변환으로 나뉘며, 객체 지향 프로그래밍에서는 업캐스팅과 다운캐스팅이 발생하고, 각 언어는 고유한 규칙과 방법을 제공하며 잘못된 형 변환은 오류를 유발할 수 있다. -
프로그래밍 구성체 -
연산자 오버로딩
연산자 오버로딩은 프로그래밍 언어에서 기존 연산자를 사용자 정의 자료형에 대해 재정의하여 내장 자료형처럼 다루도록 하는 기능으로, 코드 가독성과 표현력을 높이지만 남용 시 코드 의미를 모호하게 만들 수 있다.
2. 구조체
do-while 문의 기본 구조는 다음과 같다. 먼저 코드 블록이 실행된 후, 조건이 평가된다. 조건이 참이면 코드 블록이 다시 실행되고, 거짓이면 반복문이 종료된다. 이는 `continue` 문이 사용되지 않는 한, 다음과 동등하다.
```c
do_work();
while (condition) {
do_work();
}
```
기술적으로는 다음과 같다.
```c
while (true) {
do_work();
if (!condition) break;
}
```
또는
```c
LOOPSTART:
do_work();
if (condition) goto LOOPSTART;
```
C 언어 및 유사한 언어에서는 다음과 같은 구문을 사용한다.
```c
do
문 /* 이 부분을 "루프 본체"라고 부른다 */
while (조건);
```
이 루프의 실행은 다음과 같은 절차를 따른다.
1. "문"을 실행한다.
2. "조건"을 평가한다.
3. "조건"이 참이면, 절차의 처음으로 돌아간다. "조건"이 거짓이면, 루프를 종료한다.
"조건"이 처음부터 거짓인 경우에도, "문"은 한 번 실행된다.
루프 본체가 여러 문으로 구성된 경우, 블록 (복문)을 사용한다.
```c
do {
...
} while (조건);
3. 분기문
`while` 문과 마찬가지로 `do-while` 문에서도 break 문을 사용하여 반복문을 종료하거나, continue 문을 사용하여 조건 평가 부분으로 이동할 수 있다.
4. C/C++ 매크로에서의 활용
C/C++에서 `do-while(0)` 문은 매크로를 정의할 때 주로 사용된다. 이 방법은 여러 문장을 안전하게 묶어주고, 함수 호출과 비슷한 형태로 사용할 수 있게 해준다. `if` 문 등과 함께 사용할 때 발생할 수 있는 범위 문제를 예방하고, 코드 가독성을 높여준다.
```c
/* 두 값 x, y를 교환하는 매크로 */
#define SWAP(x, y, tmp) do { (tmp) = (x); (x) = (y); (y) = (tmp); } while (0)
```
위 코드는 `SWAP` 매크로를 `do-while(0)` 구조를 사용하여 정의한다. `x`와 `y` 값을 교환하는 여러 문장이 하나의 블록으로 묶인다.
```c
void some_function()
{
int x, y, tmp;
...
if (x > y)
SWAP(x, y, tmp);
else
puts("Not swapped.");
...
}
```
`if` 문과 함께 `SWAP` 매크로를 사용할 때, `do-while(0)` 구조는 중괄호(`{}`) 없이도 매크로가 올바르게 작동하도록 돕는다. `do-while(0)` 없이 매크로를 정의하면, `if-else` 문에서 예상치 못한 동작이 발생할 수 있다.
이러한 방식을 사용하면 "세미콜론을 붙이면 안 되는 매크로"와 같이 다루기 어려운 문제를 피할 수 있다.
5. 예제
이 예제 프로그램들은 각 언어의 do-while 루프 구문(또는 그와 유사한 기능)을 사용하여 5의 팩토리얼을 계산한다.
C 언어, C++(C++), D 언어, C#, 자바, 자바스크립트, PHP, 펄, PL/I, Visual Basic .NET, Ada, 포트란, 파스칼, Racket, 스몰토크, 파이썬 등 다양한 프로그래밍 언어에서 do-while 문 (또는 이와 유사한 기능)을 사용하는 방법은 하위 섹션을 참고할 수 있다.
5.1. C, C++, D
c
unsigned int counter = 5;
unsigned long factorial = 1;
do {
factorial *= counter--; /* 곱하고, 감소시킨다. */
} while (counter > 0);
printf("%lu\n", factorial);
```
C 언어와 C++(C++)의 예시이다.
```d
uint counter = 5;
ulong factorial = 1;
do {
factorial *= counter--;
} while (counter > 0);
writeln(factorial);
```
D 언어의 예시이다.
do-while(0) 문은 여러 개의 문을 일반 문(복합문이 아닌)으로 묶는 방법으로 C 매크로에서 흔히 사용된다. 매크로 뒤에 세미콜론이 필요하도록 하여 간단한 파서와 프로그래머에게 함수와 유사한 모양을 제공하고, `if`문과 관련된 범위 문제를 피할 수 있다. 이는 CERT C 코딩 표준 규칙 PRE10-C에서 권장된다.
5.2. C#
csharp
uint counter = 5;
ulong factorial = 1;
do
{
factorial *= counter--;
}
while (counter > 0);
System.Console.WriteLine(factorial);
```
C#의 예시이다.
5.3. Java
java
int counter = 5;
int factorial = 1;
do {
factorial *= counter--; // 곱한 다음 감소
} while (counter > 0);
System.out.println("5의 팩토리얼은 " + factorial + "입니다.");
```
자바의 예시.
5.4. 자바스크립트
javascript
var counter = 5;
var factorial = 1;
do {
factorial *= counter--;
} while (counter > 0);
console.log(factorial);
```
5.5. PHP
php
$counter = 5;
$factorial = 1;
do {
$factorial *= $counter--;
} while ($counter > 0);
echo $factorial;
?>
```
5.6. 펄
perl
$counter = 5;
$factorial = 1;
do {
$factorial *= $counter--;
} while ($counter > 0);
print $factorial;
```
코드는 다음과 같다.
```text
$counter = 5;
$factorial = 1;
do {
$factorial *= $counter--;
} while ($counter > 0);
print $factorial;
```
에서 `
5.7. PL/I
rexx
declare counter fixed initial(5);
declare factorial fixed initial(1);
do until(counter <= 0);
factorial = factorial * counter;
counter = counter - 1;
end;
put(factorial);
```
5.8. Visual Basic .NET
vbnet
Dim counter As UInteger = 5
Dim factorial As ULong = 1
Do
factorial *= counter ' 곱하기
counter -= 1 ' 감소
Loop While counter > 0
System.Console.WriteLine(factorial)
5.9. Ada
ada
with Ada.Integer_Text_IO;
procedure Factorial is
Counter : Integer := 5;
Factorial : Integer := 1;
begin
loop
Factorial := Factorial * Counter;
Counter := Counter - 1;
exit when Counter = 0;
end loop;
Ada.Integer_Text_IO.Put(Factorial);
end Main;
```
Ada의 예.
5.10. 포트란
포트란 90 이후 iteration count가 없는 형태의 do 문과 do while 문이 추가되었다.
다음은 iteration count가 없는 do 문의 예시이다.
```fortran
program FactorialProg
integer :: counter = 5
integer :: factorial = 1
do
factorial = factorial * counter
counter = counter - 1
if (counter == 0) exit
end do
print *, factorial
end program FactorialProg
```
다음은 do while 문의 예시이다.
```fortran
program FactorialProg
integer :: counter = 5
integer :: factorial = 1
factorial = factorial * counter
counter = counter - 1
do while (counter > 0)
factorial = factorial * counter
counter = counter - 1
end do
print *, factorial
end program FactorialProg
```
구형 포트란 77에는 DO-WHILE 구문이 없지만 GOTO를 사용하여 동일한 효과를 얻을 수 있다.
```fortran
INTEGER CNT,FACT
CNT=5
FACT=1
1 CONTINUE
FACT=FACT*CNT
CNT=CNT-1
IF (CNT.GT.0) GOTO 1
PRINT*,FACT
END
5.11. 파스칼
파스칼은 do-while 대신 repeat-until 구문을 사용한다.
```pascal
factorial := 1;
counter := 5;
repeat
factorial := factorial * counter;
counter := counter - 1; // Object Pascal에서는 dec (counter)를 사용할 수 있습니다.
until counter = 0;
5.12. Racket
Racket은 다른 Scheme 구현과 마찬가지로 "named-let"을 사용하여 루프를 구현하는 것이 일반적이다.
```scheme
#lang racket
(define counter 5)
(define factorial 1)
(let loop ()
(set! factorial (* factorial counter))
(set! counter (sub1 counter))
(when (> counter 0) (loop)))
(displayln factorial)
```
위 코드는 Racket의 while 루프 예제의 첫 번째 예시와 비교했을 때, named let은 인수를 취할 수 있다는 점이 다르다.
Racket과 Scheme은 적절한 do 루프 또한 제공한다.
```scheme
(define (factorial n)
(do ((counter n (- counter 1))
(result 1 (* result counter)))
((= counter 0) result) ; 정지 조건 및 반환 값.
; do-loop의 본문은 비어 있습니다.
))
5.13. 스몰토크
smalltalk
| counter factorial |
counter := 5.
factorial := 1.
[counter > 0] whileTrue:
[factorial := factorial * counter.
counter := counter - 1].
Transcript show: factorial printString
5.14. 파이썬
파이썬에는 명시적인 do-while 문이 없지만, 무한 루프와 `break` 문을 사용하여 동일한 효과를 낼 수 있다.
```python
factorial = 1
counter = 5
while True:
factorial *= counter
counter -= 1
if counter < 1:
break
print(factorial)