맨위로가기

제어 흐름

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

제어 흐름은 프로그램의 실행 순서를 결정하는 프로그래밍의 핵심 개념이다. 제어 흐름은 크게 분기, 조건, 반복, 서브루틴, 프로그램 중단 등으로 분류되며, 기계어나 어셈블리어에서는 프로그램 카운터를 수정하는 방식으로 작동한다. 구조적 프로그래밍에서는 순차 실행, 조건 분기, 반복 실행의 세 가지 제어문으로 모든 프로그래밍을 표현할 수 있으며, if-else 조건문, for 반복문 등이 널리 사용된다. 제어 흐름을 나타내는 데는 레이블, goto 문, 서브루틴, 순차, if-then-else 문, for 루프, switch case 문, while 문, do-while 문, foreach 루프 등이 사용되며, continue, break, return, retry, redo 등의 제어 구조를 통해 루프 내 흐름을 제어할 수 있다. 또한, 예외 처리, 조건, 연속, 제너레이터, 코루틴, async/await와 같은 구조적 비지역 제어 흐름을 통해 프로그램의 실행 흐름을 변경할 수 있다. 정적 분석 도구는 프로그램의 제어 흐름을 분석하는 데 사용되며, 제어 흐름 무결성과 같은 보안 기술은 소프트웨어 공격으로부터 실행 흐름을 보호하는 데 활용된다.

더 읽어볼만한 페이지

  • 제어 흐름 - 프로그램 카운터
    프로그램 카운터는 CPU 내에서 다음에 실행될 명령어의 주소를 저장하는 레지스터로, 명령어 사이클의 fetch 단계에서 사용되어 명령어를 가져오고 실행 후 갱신되며, CPU 성능 향상 기술과 현대 프로그래밍 모델에 영향을 미친다.
  • 제어 흐름 - 예외 처리
    예외 처리는 프로그램 실행 중 예외 발생 시 정상적인 실행 흐름을 유지하거나 안전하게 종료하기 위한 메커니즘으로, 많은 프로그래밍 언어에서 제공하며 예외 안전성을 목표로 한다.
제어 흐름
개요
정의컴퓨터 과학에서 프로그램의 명령어 실행 순서
관련 용어실행 흐름
설명명령어, 함수, 구문 호출 순서
컴퓨터가 코드를 실행하는 순서
종류
기본적인 제어 흐름순차적인 실행
선택 (분기)
반복
함수 호출
변경 방법서브루틴
조건문
반복문
예외 처리
코루틴
계속
루프 구성체
종류Do-while 루프
While 루프
For 루프
Foreach 루프
무한 루프

2. 범주

프로그램 언어마다 제어 흐름을 나타내는 구문, 즉 제어문의 종류는 다양하지만, 실행 방식에 따라 다음과 같이 분류할 수 있다.


  • 다른 구문에서 시작 (무조건 분기, 점프)
  • 어떠한 조건 만족 시 한 구문의 집합을 실행 (조건 분기)
  • 어떠한 조건이 만족 될 때까지 한 구문의 집합을 실행 (loop 구문)
  • 현재 실행 구문에서 떨어진 한 구문의 집합을 실행 (서브루틴, 코루틴, 컨티뉴에이션)
  • 프로그램 실행을 중단 (무조건 중지)


에츠허르 데이크스트라구조화 이론에서 모든 프로그래밍은 순차 실행, 조건 분기, 반복 실행의 3가지 제어문 구문 유형으로 기술될 수 있음을 언급하였다.[56][57]

3. 종류

제어 흐름을 나타내는 구문, 곧 제어문의 종류는 각 프로그램 언어마다 다르나, 구문들의 실행 방식에 따라 분류할 수 있다.


  • 다른 구문에서 시작 (무조건 분기, 점프)
  • 어떠한 조건 만족 시 한 구문의 집합을 실행 (조건 분기)
  • 어떠한 조건이 만족 될 때까지 한 구문의 집합을 실행 (loop 구문)
  • 현재 실행 구문에서 떨어진 한 구문의 집합을 실행 (서브루틴)
  • 프로그램 실행을 중단 (무조건 중지)


에츠허르 데이크스트라구조화 이론에서 모든 프로그래밍은 순차 실행, 조건 분기, 그리고 반복 실행의 3개의 제어문 구문 유형으로 기술될 수 있음을 언급하였다.[56][57]

조건 분기 구문으로는 'if ~ else ~' 조건문이, 반복 실행 구문으로는 'for (~; ~; ~)' 반복문이 여러 프로그래밍 언어에서 주로 사용되고 있으며, 순차적 실행을 위해서는 'main()' 함수 같은 특정 초기 실행 함수가 예약되어 있다.

펩타이드 이온 질량 매핑 검색 프로세스의 상태 다이어그램

3. 1. 레이블 (Labels)

레이블은 소스 코드 내의 특정 위치를 가리키는 명시적인 이름 또는 숫자이며, 제어 흐름 문에서 참조되어 해당 위치로 이동하는 데 사용된다.[41]

행 번호는 BASIC과 같은 일부 언어에서 사용되는 레이블의 대안이다. 행 번호는 소스 코드의 각 줄의 시작 부분에 배치된 정수이다. 이러한 숫자를 사용하는 언어는 행 번호가 각 다음 줄에서 증가해야 한다는 제약이 있지만, 연속적일 필요는 없다. 예를 들어 BASIC에서 행 번호는 시스템이 재정렬해주는 편리함이 있었다.

C나 Ada와 같은 언어에서 레이블은 식별자이며, 문 앞에 쓰이고 바로 뒤에 콜론(:)이 붙는다.

ALGOL 60 언어는 레이블로 식별자와 정수를 모두 허용했지만(콜론으로 다음 문과 연결), 다른 ALGOL 계열 언어에서는 정수를 레이블로 허용하는 경우가 거의 없었다. 초기 Fortran 컴파일러는 정수만 레이블로 허용했고, Fortran-90부터 영숫자 레이블도 허용되었다.

3. 2. Goto 문

goto 문은 지정된 레이블로 제어 흐름을 무조건적으로 옮기는 가장 기본적인 형태의 제어문이다.[41] goto 문의 효과는 다음에 실행될 문이 지정된 레이블에 나타나거나 그 직후에 나타나는 문이 되도록 하는 것이다. 많은 컴퓨터 과학자, 특히 데이크스트라는 goto 문의 사용을 해로운 것으로 간주하였으며, 구조적 프로그래밍에서는 지양된다.[42]

3. 3. 서브루틴 (Subroutines)

서브루틴은 절차, 루틴, 프로시저, 함수(특히 값을 반환하는 경우), 메서드(특히 어떤 클래스에 속하는 경우) 등 다양한 명칭으로 불린다.[1]

1950년대, 컴퓨터의 메모리는 매우 작았기 때문에 서브루틴의 첫 번째 목적은 프로그램의 크기를 줄이는 데 있었다.[1] 서브루틴으로 작성된 코드를 프로그램 내 여러 곳에서 사용함으로써 프로그램 전체의 코드 크기를 줄일 수 있었다.[1] 현재는 서브루틴은 프로그램을 구조화하기 위해 사용된다.[1] 즉, 특정 알고리즘을 분리하거나, 특정 데이터에 접근하는 메서드를 숨기는 것이다.[1] 다수의 프로그래머가 공동으로 프로그램 개발을 하는 경우, 서브루틴은 일종의 모듈성을 제공하며, 업무 분담점 역할도 한다.[1]

서브루틴에 인수가 있다면 더욱 편리해진다.[1] 많은 프로그래밍 언어에는 제곱근을 구하는 서브루틴이 내장되어 있으며, 인수로 제곱근을 구하고 싶은 수를 제공할 수 있다.[1]

프로그래밍 언어에 따라 재귀 호출이 가능하다.[1] 즉, 서브루틴이 직접적 또는 간접적으로 자기 자신을 호출할 수 있다.[1] 퀵 정렬이나 트리 구조를 탐색하는 알고리즘 등은 재귀를 사용하는 것이 더 자연스럽게 표현할 수 있다.[1]

서브루틴을 사용하면 인수 전달, 서브루틴 호출, 호출 스택 처리, 서브루틴으로부터의 복귀 등의 오버헤드로 인해 프로그램 성능이 약간 저하된다.[1] 실제 오버헤드는 하드웨어 및 소프트웨어 아키텍처에 따라 달라진다.[1] 컴파일러에 따라서는 인라인 전개를 효과적으로 사용하여 오버헤드 감소를 꾀하는 경우도 있다.[1]

프로그래밍 언어에 따라 서브루틴의 물리적인 마지막에 도달해야 서브루틴에서 복귀할 수 있는 방식도 있다.[1] 다른 언어에는 '''return''' 또는 '''exit''' 문이 있다.[1] 이는 서브루틴의 마지막으로의 분기와 동일하며, 제어 구조를 복잡하게 만들지 않는다.[1] 필요에 따라 여러 개의 해당 문을 서브루틴 내에 배치할 수 있다.[1]

3. 4. 순차 (Sequence)

구조적 프로그래밍에서, 연속적인 명령의 정렬된 순서는 반복, 재귀 및 선택과 함께 프로그램의 구성 요소로 사용되는 기본적인 제어 구조 중 하나로 간주된다.[42]

다음은 엉뚱하게 키워드에 집착하는 듯하지만, 이러한 어구에 얽매이기보다는 구문(syntax)으로 종합적으로 파악하면 크게 신경 쓸 필요는 없다.

; 종료 키워드가 없는 언어

: 알골 60, C, C++, 하스켈, Java, 파스칼, Perl, PHP, PL/I, 파이썬, PowerShell 등. 이 종류의 언어는 문장의 나열을 묶음(블록)으로 만드는 어떤 방법을 가지고 있다.

:* 알골 60, 파스칼: `begin` ... `end`

:* C, C++, Java, Perl, PHP, PowerShell: 중괄호 사용 `{` ... `}`

:* PL/1: `DO` ... `END`

:* 파이썬: 들여쓰기 레벨 사용 (오프사이드 규칙 참조)

:* 하스켈: 들여쓰기 레벨이나 중괄호를 사용할 수 있으며, 자유롭게 혼합 가능

; 종료 키워드가 있는 언어

: 에이다, 알골 68, Modula-2, 포트란 77, Visual Basic 등. 종료 키워드는 몇 가지 종류가 있다.

:* 에이다, 포트란 90: 종료 키워드는 `end` + 공백 + 시작 키워드. 예를 들어, `if` ... `end if`, `loop` ... `end loop`

:* 알골 68: 시작 키워드를 거꾸로 표기. 예를 들어, `if` ... `fi`, `case` ... `esac`

:* 포트란 77: 종료 키워드는 `end` + 시작 키워드. 예를 들어 `IF` ... `ENDIF`, `DO` ... `ENDDO`

:* Modula-2: 시작 키워드에 관계없이 항상 `END`라는 종료 키워드를 사용.

:* Visual Basic: 제어 구조마다 고유한 종료 키워드. `If` ... `End If`; `For` ... `Next`; `Do` ... `Loop`; `While` ... `Wend`

3. 5. If ... then ... (else) 문

If ... then ... (else) 문은 조건에 따라 코드 블록의 실행 여부를 결정하는 조건문이다. 여러 프로그래밍 언어에서 널리 사용된다.

기본적인 형태는 다음과 같다.

  • `if (조건문) then (구문)`: 조건문을 만족하면 해당 구문을 수행한다.
  • `if (조건문) then (구문1) else (구문2)`: 조건문을 만족하면 구문 1을 수행하고, 그렇지 않다면 구문 2를 수행한다.


대부분의 프로그래밍 언어는 `if` 문을 지원하며, 언어에 따라 문법에 차이가 있다. 크게 최종 키워드(예: `endif`)의 유무에 따라 두 그룹으로 나눌 수 있다.

  • 최종 키워드 없음: ALGOL 60, C, C++, Go, Haskell, Java, 파스칼, Perl, PHP, PL/I, Python, PowerShell 등이 있다. 이 언어들은 문장을 묶어 블록으로 만드는 별도의 방법이 필요하다.
  • ALGOL 60, 파스칼: `begin` ... `end`
  • C, C++, Go, Java, Perl, PHP, PowerShell: 중괄호 (`{` ... `}`)
  • PL/I: `DO` ... `END`
  • Python: 들여쓰기 수준 ( Off-side 규칙 참조)
  • Haskell: 들여쓰기 수준 또는 중괄호를 사용, 자유롭게 혼합 가능
  • Lua: `do` ... `end`를 사용한다.
  • 최종 키워드 있음: Ada, APL, ALGOL 68, Modula-2, Fortran 77, Mythryl, Visual Basic 등이 있다. 최종 키워드의 형태는 다양하다.
  • Ada: `end` + ''space'' + 초기 키워드 (예: `if` ... `end if`)
  • APL: 선택적으로 `:End` + 초기 키워드 (예: `:If` ... `:End` 또는 `:If` ... `:EndIf`)
  • ALGOL 68, Mythryl: 초기 키워드를 거꾸로 쓴다 (예: `if` ... `fi`)
  • Fortran 77: `END` + 초기 키워드 (예: `IF` ... `ENDIF`)
  • Modula-2: 모든 것에 동일한 최종 키워드 `END`
  • Visual Basic: 모든 제어 구조에 자체 키워드가 있다 (예: `If` ... `End If`)


다음은 여러 언어에서 `if...then...else` 문의 사용 예시를 보여주는 표이다.


3. 6. For 루프

For 루프는 지정된 횟수만큼 코드 블록을 반복 실행하는 반복문이다.[4][5][6] 대부분의 프로그래밍 언어는 특정 횟수만큼 루프를 반복하는 구문을 제공한다.

C, C++, Java 등에서는 초기화, 조건, 증감식을 사용하여 반복을 제어한다.

파스칼포트란C/C++/Java



위 예시들에서 N이 1보다 작으면, 루프 본문은 프로그래밍 언어에 따라 한 번 (I 값이 1일 때) 실행되거나 아예 실행되지 않을 수 있다.

대부분의 경우 카운트는 증가뿐만 아니라 감소할 수도 있으며, 1이 아닌 다른 값으로 증감하도록 설정할 수도 있다. 많은 프로그래밍 언어에서 정수만 카운트 제어 루프에서 안정적으로 사용할 수 있다. 부동 소수점 숫자는 하드웨어 제약으로 인해 부정확하게 표현되기 때문이다.

예를 들어 다음과 같은 루프를 고려해 보자.

'''for''' X := 0.1 '''step''' 0.1 '''to''' 1.0 '''do'''

이 루프는 반올림 오류, 하드웨어, 컴파일러 버전에 따라 9번 또는 10번 반복될 수 있다. 또한 X의 증분이 반복적인 덧셈으로 발생하면 누적된 반올림 오류로 인해 각 반복에서 X의 값이 예상 시퀀스 0.1, 0.2, 0.3, ..., 1.0과 상당히 다를 수 있다.

C 언어의 `for`문과 Common Lisp의 `do` 형식과 같은 일반적인 반복 구성은 여러 컬렉션을 병렬로 반복하는 등 다양한 루프를 표현하는 데 사용될 수 있다. 그러나 더 구체적인 루프 구문을 사용할 수 있는 경우, 표현식의 목적을 더 명확하게 나타내기 때문에 일반적으로 일반적인 반복 구문보다 선호된다.

3. 7. Switch case 문

Switch 문은 주어진 값을 여러 상수와 비교하여 각 case 절 중 하나를 선택하여 실행하는 제어문이다. C, C++, Java 등에서 사용되며, 효율적인 분기 처리를 가능하게 한다.[1]

명시된 값에 해당하는 case 절로 이동하여 해당 구문을 수행한다. 해당되는 case가 없을 때는 default 절을 수행한다.[1]

```c

switch (value) {

case '1': statement1; break;

case '2': statement2; break;

case '3': statement3; break;

default: statementD;

}

```

Switch 구문 (또는 ''case 구문'' 또는 ''다중 분기'')은 주어진 값을 지정된 상수와 비교하여 일치하는 첫 번째 상수에 따라 작업을 수행한다. 일반적으로 일치하는 항목이 없으면 기본 작업("else", "otherwise")을 수행하는 규정이 있다. Switch 구문은 조회 테이블과 같은 컴파일러 최적화를 허용할 수 있다.[1] 동적 언어에서는 케이스가 상수 표현식으로 제한되지 않을 수 있으며, 패턴 매칭으로 확장될 수 있다.[1]


3. 8. While 문

While 문은 조건이 참인 동안 코드 블록을 반복해서 실행하는 제어 흐름문의 한 종류이다. C, C++, Java 등 다양한 프로그래밍 언어에서 사용된다. While 문은 조건을 루프 시작 부분에서 검사하거나 끝 부분에서 검사할 수 있다.

  • 시작 시점 검사: 조건을 루프 시작 시점에 검사하면, 조건이 처음부터 거짓인 경우 코드 블록이 한 번도 실행되지 않을 수 있다.
  • 끝 시점 검사: 조건을 루프 끝에서 검사하면, 코드 블록이 최소한 한 번은 실행된다.


시작 시점 검사끝 시점 검사



위 표에서 'xxx'는 반복해서 실행될 코드 블록을 나타낸다. C, C++, Java 등의 언어에서는 중괄호(`{}`)를 사용하여 코드 블록을 표현한다.

3. 9. Do-while 문

Do-while 문은 While 문과 유사하지만, 코드 블록을 최소 한 번 실행한 후 조건을 검사하는 반복문이다.[1]

```

'''do'''

xxx

'''while''' (test);

```

위와 같은 형태로 사용되며, xxx로 표시된 코드 블록을 우선 실행한 후, test 조건식을 검사하여 참이면 다시 xxx를 실행하고, 거짓이면 반복을 중단한다.[1]

3. 10. Foreach 루프 (Collection-controlled loops)

몇몇 프로그래밍 언어(예: Ada, D, C++11, 스몰토크, PHP, Perl, 오브젝트 파스칼, 자바, C#, MATLAB, Visual Basic, 루비, 파이썬, 자바스크립트, 포트란 95 및 이후 버전)는 배열의 모든 요소 또는 집합이나 컬렉션의 모든 멤버를 암시적으로 반복하는 특수 구문을 가지고 있다.

```text

someCollection '''do''': [:eachElement |xxx].

'''for''' Item '''in''' Collection '''do''' '''begin''' xxx '''end''';

'''foreach''' (item; myCollection) { xxx }

'''foreach''' someArray { xxx }

'''foreach''' ($someArray as $k => $v) { xxx }

Collection coll; '''for''' (String s : coll) {}

'''foreach''' ('''string''' s '''in''' myStringCollection) { xxx }

someCollection | ForEach-Object { $_ }

'''forall''' ( index = first:last:step... )

```

스칼라는 컬렉션 제어 루프를 일반화하고 비동기 프로그래밍과 같은 다른 용도를 지원하는 for 표현식을 가지고 있다. 하스켈은 do 표현식과 comprehension을 가지고 있으며, 이는 스칼라의 for 표현식과 유사한 기능을 함께 제공한다.

3. 11. 기타 제어 구조

'''Continue 문'''은 루프 내에서 현재 반복을 건너뛰고 다음 반복을 시작하게 하는 제어 구조이다. 대부분의 언어에서 `continue` 구문을 사용하며, `skip`[8], 포트란의 `cycle`, 펄과 루비의 `next` 등의 명령어를 사용하기도 한다.

'''Break 문'''은 루프를 즉시 종료하고 루프 다음의 코드를 실행하게 하는 제어 구조이다. 대부분의 언어에서 `break` 구문을 사용하며, Visual Basic의 `Exit`, Perl의 `last` 등의 명령어를 사용하기도 한다.

'''Return 문'''은 함수 또는 서브루틴을 종료하고 호출 지점으로 돌아가게 하는 제어 구조이다. 서브루틴 내의 루프에서 `return`을 사용하면 중첩된 루프에서도 탈출할 수 있다.

'''Retry 문'''은 Ruby에서 사용되며, 루프 전체를 처음부터 다시 시작하게 한다.[11]

'''Redo 문'''은 Perl[9]과 Ruby[10]에서 사용되며, 현재 반복을 처음부터 다시 실행한다.

'''다단계 중단 (Multilevel break)'''은 중첩된 루프에서 한 번에 여러 레벨을 벗어나는 기능이다. bash[12] 및 PHP[13]와 같이 다단계 중단(''N'' 단계에서 중단)을 지원하거나, Go, Java 및 Perl[14]과 같이 레이블이 지정된 중단(지정된 레이블에서 중단하고 계속)을 지원하는 언어도 있다. C에는 다단계 중단 기능이 없으며, `goto` 문을 사용하여 레이블이 지정된 중단을 구현하는 것이 일반적인 대안이다.[15] 파이썬에는 다단계 중단 또는 계속 기능이 없다.[16]

4. 구조적 비지역 제어 흐름 (Structured non-local control flow)

많은 프로그래밍 언어, 특히 보다 동적인 프로그래밍 스타일을 선호하는 언어들은 '비지역 제어 흐름'을 위한 구문을 제공한다. 이는 실행 흐름이 특정 컨텍스트에서 벗어나 미리 선언된 지점에서 재개되도록 한다. ''조건'', ''예외'' 및 ''계속''은 세 가지 일반적인 종류의 비지역 제어 구문이다. 제너레이터, 코루틴 및 async 키워드와 같은 더 특이한 것들도 존재한다.

프로그래밍 언어조건예외
AdaNoYes
CNoNo
C++NoYes
C#NoYes
Common LispYesNo
DNoYes
EiffelNoYes
HaskellNoYes
JavaNoYes
Objective-CNoYes
PHPNoYes
PL/IYesNo
파이썬NoYes
REBOLYesYes
RubyNoYes
Visual Basic .NETYesYes
Windows PowerShellNoYes


4. 1. 예외 처리 (Exception Handling)

현대 프로그래밍 언어는 `GOTO` 문을 사용하지 않고 예외 처리를 위한 특수한 구조를 사용한다. 예를 들어, C++에서는 다음과 같은 코드를 사용한다.[24]

```cpp

try {

xxx1 // 이 안의 어디선가 다음을 사용한다

xxx2 // '''throw''' someValue;

xxx3

} catch (someClass& someId) { // someClass의 경우를 캐치

actionForSomeClass

} catch (someType& anotherId) { // someType의 경우를 캐치

actionForSomeType

} catch (...) { // 이미 캐치되지 않은 임의의 값을 캐치

actionForAnythingElse

}

```

위의 예시처럼 여러 개의 `catch` 절을 사용할 수 있다. 특정 `throw`에 일치하는 `catch`가 없으면, 제어는 서브루틴 호출이나 중첩된 블록을 거쳐 일치하는 `catch`가 발견될 때까지, 또는 메인 프로그램의 끝에 도달할 때까지 다시 올라간다. 메인 프로그램까지 도달했는데도 `catch`가 없으면 프로그램은 오류 메시지를 출력하고 강제로 중지된다.[24]

C++의 영향을 받아 `catch`는 Java나 C#과 같은 다른 언어에서 패턴 매칭 예외 처리기를 선언하기 위해 예약된 키워드로 널리 사용된다. Ada와 같은 일부 다른 언어는 `exception` 키워드를 사용하여 예외 처리기를 도입한 다음 패턴 매칭을 위해 다른 키워드(Ada의 `when`)를 사용하기도 한다. AppleScript와 같은 몇몇 언어는 예외가 발생했을 때 여러 정보를 자동으로 추출하기 위해 예외 처리기 구문에 자리 표시자를 통합한다. 이 접근 방식은 AppleScript의 `on error` 구조로 아래에 예시되어 있다.[24]

```applescript

try

set myNumber to myNumber / 0

on error e number n from f to t partial result pr

if ( e = "Can't divide by zero" ) then display dialog "You must not do that"

end try

```

데이비드 와트(David Watt)는 2004년 교과서에서 시퀀서의 프레임워크 내에서 예외 처리를 분석했다. 그는 산술 오버플로우 또는 파일이 없는 경우와 같은 입출력 실패와 같이 일반적으로 예시되는 비정상적인 상황이 "어떤 저수준 프로그램 단위에서 감지되지만, 처리기가 더 자연스럽게 고수준 프로그램 단위에 위치하는" 오류의 일종이라고 언급했다. 예를 들어, 프로그램은 여러 번의 파일 읽기 호출을 포함할 수 있지만, 파일이 발견되지 않을 때 수행할 작업은 프로그램에서 해당 파일의 의미(목적)에 따라 달라지므로 이 비정상적인 상황에 대한 처리 루틴은 저수준 시스템 코드에 위치할 수 없다. 와트는 또한 단일 종료 구조적 프로그래밍 또는 (다중 종료) 반환 시퀀서와 같이 호출자에서 상태 플래그 검사를 도입하면 "응용 프로그램 코드가 상태 플래그 테스트로 얽히는 경향이 있으며" "프로그래머가 부주의하거나 게으르게 상태 플래그를 테스트하는 것을 생략할 수 있습니다. 실제로, 상태 플래그로 표시되는 비정상적인 상황은 기본적으로 무시됩니다!"라고 언급했다. 와트는 상태 플래그 테스트와는 대조적으로 예외는 반대 기본 동작을 가지며, 프로그램이 명시적으로 무시하는 코드를 추가하는 것을 포함하여 어떤 방식으로든 예외를 명시적으로 처리하지 않으면 프로그램을 종료시킨다고 언급한다. 이러한 주장에 따라 와트는 점프 시퀀서 또는 이스케이프 시퀀서가 위에서 논의된 의미론을 가진 전용 예외 시퀀서로 덜 적합하다고 결론 내린다.[24]

Object Pascal, D, Java, C#, Python에서는 `finally` 절을 `try` 구조에 추가할 수 있다. 제어가 `try`를 어떻게 벗어나든, `finally` 절 내부의 코드는 실행이 보장된다. 이 기능은 처리 완료 시 열린 파일이나 데이터베이스 연결과 같은 비용이 많이 드는 리소스를 해제해야 하는 코드를 작성할 때 유용하다.[24]

```csharp

FileStream stm = null; // C# 예시

try {

stm = new FileStream("logfile.txt", FileMode.Create);

return ProcessStuff(stm); // 예외 발생 가능

} finally {

if (stm != null)

stm.Close();

}

```

이 패턴은 매우 일반적이므로 C#에는 특별한 구문이 있다.[24]

```csharp

using (var stm = new FileStream("logfile.txt", FileMode.Create)) {

return ProcessStuff(stm); // 예외 발생 가능

}

```

`using` 블록을 벗어날 때 컴파일러는 `stm` 객체가 해제되도록 보장하여 파일을 초기화하고 해제하는 부작용에서 추상화하면서 변수를 파일 스트림에 효과적으로 이름 바인딩한다. Python의 `with` 문과 Ruby의 `File.open`에 대한 블록 인수는 비슷한 효과를 내는 데 사용된다.[24]

위에 언급된 모든 언어는 표준 예외와 예외가 발생하는 상황을 정의한다. 사용자는 자신만의 예외를 발생시킬 수 있다. C++는 사용자가 `int`와 같은 기본 유형을 포함하여 거의 모든 유형을 throw하고 catch할 수 있도록 허용하는 반면, Java와 같은 다른 언어는 덜 허용적이다.[24]

4. 2. 조건 (Conditions)

PL/I는 ZERODIVIDE, SUBSCRIPTRANGE, ENDFILE 등 약 22개의 표준 조건을 제공하며, 프로그래머가 자체적으로 이름을 붙인 조건을 정의하고 사용할 수도 있다. 이러한 조건은 `ON ''condition'' action;` 구문을 통해 가로챌 수 있다.

`ON` 문에는 단 하나의 명령문만 지정할 수 있으므로, 제어 흐름이 어디서 다시 시작되어야 하는지를 결정하기 위해 많은 경우 `GOTO`문이 필요하다.

일부 구현에서는 조건 처리, 특히 SUBSCRIPTRANGE에 상당한 오버헤드가 발생하여 많은 프로그래머들이 조건을 사용하지 않으려고 했다.

일반적인 구문 예시는 다음과 같다.

`'''ON''' ''condition'' '''GOTO''' ''label''`

4. 3. 연속 (Continuations)

연속은 프로그램 실행의 특정 지점을 저장하고 나중에 해당 지점에서 실행을 재개할 수 있도록 하는 메커니즘이다.

4. 4. 제너레이터 (Generators)

제너레이터는 세미코루틴이라고도 하며, Python 등의 프로그래밍 언어에서 yield영어 키워드를 사용하여 제어 흐름을 소비자 메서드로 일시적으로 양보할 수 있도록 하는 기능이다.[1] 이를 통해 함수의 실행을 일시 중지했다가 나중에 다시 시작할 수 있다.

4. 5. 코루틴 (Coroutines)

코루틴은 서로에게 제어 권한을 양보할 수 있는 함수로, 협력적 멀티태스킹의 한 형태이며, 스레드를 사용하지 않는다.

코루틴은 프로그래밍 언어가 연속체 또는 제너레이터를 제공하는 경우 라이브러리로 구현할 수 있으며, 실제로 코루틴과 제너레이터의 차이는 기술적인 세부 사항이다.

4. 6. Async/Await

C# 5.0은 "직접 스타일"로 비동기 I/O를 지원하기 위해 `async` 키워드를 도입했다.[1]

5. 도구

프로그램에는 제어 흐름과 관련된 많은 구문들이 있다. 또한 프로그램 실행 상의 제어 흐름 또한 무수히 존재한다. 실제로 직접 이러한 프로그램 상의 제어 흐름을 일일이 확인하기는 힘든 일이다. 이러한 소모적인 작업을 대신해 주는 정적 분석 도구를 사용하면 사람이 직접 분석을 할 때의 시간 및 노력을 절약할 수 있다.

6. 제안된 제어 구조

도널드 커누스는 1974년 논문에서 기존 제어 구조로는 다루기 어려운 상황들을 제시하고, 이를 처리할 수 있는 새로운 제어 구조들을 제안했다.[32] 이러한 제안들은 유용함에도 불구하고 아직 주류 프로그래밍 언어에는 도입되지 않았다.

커누스가 제안한 구조는 다음과 같다.


  • 다중 조건 루프: 1972년 달이 제안한 구조로,[33] `loop`, `while`, `repeat` 키워드를 사용하여 루프의 시작, 중간, 끝에 조건을 설정할 수 있다.
  • `xxx1`이 생략되면 테스트가 상단에 있는 `while` 루프와 동일하다.
  • `xxx2`가 생략되면 테스트가 하단에 있는 `do while` 루프와 동일하다.
  • `while`이 생략되면 무한 루프가 된다.
  • 이 구조는 중간에 `while` 검사가 있는 `do` 루프라고 생각할 수 있으며, 대부분의 프로그래밍 언어에서 여러 구조를 대체할 수 있다.


```

'''loop'''

xxx1

'''while''' test;

xxx2

'''repeat''';

```

  • 이벤트 기반 제어 (exitwhen): 1974년 Zahn이 제안한 구조로,[34] `exitwhen`, `exits`, `endexit` 키워드를 사용하여 특정 이벤트 발생 시 해당 이벤트에 연결된 코드를 실행하고 제어 흐름을 변경한다.
  • `exitwhen`은 `xxx` 내에서 발생할 수 있는 이벤트를 지정한다.
  • 이벤트 발생은 해당 이벤트 이름을 명령문으로 사용하여 나타낸다.
  • 어떤 이벤트가 발생하면 관련 동작이 수행된 다음 `endexit` 바로 뒤로 제어가 이동한다.
  • 이 구조는 어떤 상황이 적용되는지 결정하는 것과 해당 상황에 대해 수행할 동작을 명확하게 분리한다.
  • 예외 처리와 개념적으로 유사하며, 많은 언어에서 예외 또는 유사한 구조가 이 목적으로 사용된다.


```

'''exitwhen''' EventA '''or''' EventB '''or''' EventC;

xxx

'''exits'''

EventA: actionA

EventB: actionB

EventC: actionC

'''endexit''';

```

예시: 2차원 배열에서 특정 항목 검색

```

'''exitwhen''' found '''or''' missing;

'''for''' I := 1 '''to''' N '''do'''

'''for''' J := 1 '''to''' M '''do'''

'''if''' table[I,J] = target '''then''' found;

missing;

'''exits'''

found: print ("item is in table");

missing: print ("item is not in table");

'''endexit''';

```

에이다에서는 `loop` - `end loop` 구조 내에서 `exit when` 절을 사용하여 중간 탈출을 구현할 수 있다.

```ada

with Ada.Text_IO;

with Ada.Integer_Text_IO;

procedure Print_Squares is

X : Integer;

begin

Read_Data : loop

Ada.Integer_Text_IO.Get(X);

exit Read_Data when X = 0;

Ada.Text_IO.Put (X * X);

Ada.Text_IO.New_Line;

end loop Read_Data;

end Print_Squares;

7. 보안

제어 흐름 무결성 기술, 스택 카나리, 버퍼 오버플로우 보호, 섀도 스택, 가상 함수 테이블 포인터 검증을 포함한 다양한 기술은 프로그램의 실행 흐름을 우회하는 소프트웨어 공격을 방어하는데 사용된다.[1]

참조

[1] 논문 "Flow diagrams, turing machines and languages with only two formation rules" Comm. ACM 1966-05
[2] 웹사이트 Loop Exits and Structured Programming: Reopening the Debate http://cs.stanford.e[...] ACM SIGCSE Bulletin 2014-07-25
[3] 서적 Programming language design concepts John Wiley & Sons
[4] 웹사이트 Nested Loops in C with Examples https://www.geeksfor[...] 2019-11-25
[5] 웹사이트 Python Nested Loops https://www.w3school[...]
[6] 웹사이트 Nested Loops https://medium.com/s[...] 2019-11-22
[7] 문서 Ada Programming: Control: Endless Loop
[8] 웹사이트 What is a loop and how we can use them? http://www.megacpptu[...]
[9] 웹사이트 redo - perldoc.perl.org https://perldoc.perl[...]
[10] 웹사이트 control_expressions - Documentation for Ruby 2.4.0 https://docs.ruby-la[...]
[11] 웹사이트 control_expressions - Documentation for Ruby 2.3.0 https://docs.ruby-la[...]
[12] 문서 Advanced Bash Scripting Guide: 11.3. Loop Control http://tldp.org/LDP/[...]
[13] 문서 PHP Manual: break http://php.net/manua[...]
[14] 문서 perldoc: last http://perldoc.perl.[...]
[15] 문서 comp.lang.c FAQ list · Question 20.20b http://c-faq.com/mis[...]
[16] 문서 "[Python-3000] Announcing PEP 3136" http://mail.python.o[...] Guido van Rossum
[17] 서적 Mathematics of Program Construction http://www.cs.cornel[...] 2008
[18] 간행물 Structured Programming with go to Statements
[19] 서적 Programming language design concepts John Wiley & Sons
[20] 서적 Eiffel: The Language Prentice Hall
[21] 웹사이트 Common Lisp LOOP macro http://www.lispworks[...]
[22] 웹사이트 for_each http://www.sgi.com/t[...]
[23] 웹사이트 Chapter 1. Boost.Foreach http://boost-sandbox[...] 2010-01-29
[24] 서적 Programming language design concepts John Wiley & Sons
[25] 웹사이트 Asyncio: Asynchronous I/O: Python 3.10.2 documentation https://docs.python.[...]
[26] 웹사이트 Socketry/Async https://github.com/s[...] 2022-02-25
[27] 웹사이트 Generators - the Rust Unstable Book https://docs.rust-la[...]
[28] 웹사이트 Corona - Rust https://docs.rs/coro[...]
[29] 웹사이트 Getting Started - Asynchronous Programming in Rust https://rust-lang.gi[...]
[30] 웹사이트 Jitsi Meet http://storm-enroute[...] Storm-enroute.com
[31] 웹사이트 "We don't know where to GOTO if we don't know where we've COME FROM. This (spoof) linguistic innovation lives up to all expectations." http://www.fortran.c[...] 2018-07-16
[32] 논문 "Structured Programming with go to Statements" ACM Computing Surveys 1974-12
[33] 서적 "Structured Programming" Academic Press 1972
[34] 논문 "A control statement for natural top-down structured programming" presented at Symposium on Programming Languages, Paris 1974
[35] 웹사이트 On differences between the CFI, CPS, and CPI properties https://nebelwelt.ne[...]
[36] 웹사이트 Adobe Flash Bug Discovery Leads To New Attack Mitigation Method http://www.darkreadi[...] 2015-11-10
[37] 간행물 Endgame to Present at Black Hat USA 2016 http://www.prnewswir[...]
[38] 문서 procedural programming
[39] 문서 imperative programming
[40] 서적 bit 単語帳 共立出版 1990-08-15
[41] URL https://gcc.gnu.org/[...]
[42] 논문 Flow diagrams, turing machines and languages with only two formation rules 1966-05
[43] 서적 Eiffel: The Language Prentice Hall
[44] URL Predicates and Specification Expressions http://www.eecs.ucf.[...]
[45] 웹사이트 Common Lisp LOOP macro http://www.lispworks[...]
[46] URL for_each http://www.sgi.com/t[...] Sgi.com 2010-11-09
[47] URL Chapter 1. Boost.Foreach http://boost-sandbox[...] Boost-sandbox.sourceforge.net 2009-12-19
[48] 문서 LOOP は独自の分岐構文を内包している
[49] 문서 ただし、標準ライブラリに無限ループを実現するloopメソッドが存在する。 http://docs.ruby-lan[...]
[50] 논문 Structured Programming with go to Statements 1974-12
[51] 서적 Structured Programming Academic Press 1972
[52] 간행물 A control statement for natural top-down structured programming
[53] URL We don't know where to GOTO if we don't know where we've COME FROM. This (spoof) linguistic innovation lives up to all expectations. http://www.fortran.c[...] DATAMATION 1973-12
[54] URL http://catb.org/jarg[...]
[55] URL http://www.nurs.or.j[...]
[56] 문서 Notes on Structured Programming http://www.cs.utexas[...]
[57] 문서 레드햇리눅스Ver5.2 사이버출판사 송창훈1999 - 6장 쉘스크립트작성과활용 (structured theorem)



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com