4-5.그 외의 제어문

4-5-가.goto

goto문은 지정한 곳으로 무조건 점프하는 제어문이다. goto라는 말이 의미하듯이 조건없이 무조건 제어를 옮겨 버리기 때문에 사실 가장 사용하기 쉬운 제어문이다. goto로 제어를 옮길 지점은 레이블(label)이라는 것으로 표식을 단다. 블록의 끝만 제외하고 프로그램의 어느 곳에나 레이블을 배치해 놓고 goto 레이블명; 이라는 명령을 내리면 레이블 위치로 즉시 이동한다. 레이블보다 앞에서 뒤로 이동할 수도 있고 뒤에서 앞으로 이동할 수도 있되 단 함수 내에서만 이동할 수 있으며 다른 함수로는 점프할 수 없다.

레이블은 일종의 명칭이므로 명칭 규칙에만 맞으면 자유롭게 작성할 수 있다. 레이블 다음에 콜론(:)을 붙여 점프할 위치에 삽입해 놓기만 하면 된다. 다음이 goto문의 사용예이다.

 

here:

.....

.....

goto here;

 

점프하기를 원하는 곳에 here라는 이름으로 레이블을 붙여 놓고 goto here; 명령을 내리면 즉시 here 다음의 문장으로 이동한다. 다른 순환문과는 달리 복잡한 형식을 필요로 하지 않기 때문에 처음부터 제어 구조를 설계할 필요도 없고 언제든지 어느 곳으로나 제어를 옮길 수 있는 무척 간편한 명령이다.

goto문과 조건문을 사용하면 모든 종류의 반복문을 다 흉내낼 수 있다. if문으로 반복을 계속할 것인지 판단해 보고 루프 처음으로 점프해 버리면 된다. 1~100까지 합계를 구하는 예제를 반복문없이 작성해 보자.

 

: gotosum

#include <Turboc.h>

 

void main()

{

     int i, sum;

 

     i=1;

     sum=0;

here:

     sum=sum+i;

     if (i<100) {

          i=i+1;

          goto here;

     }

     printf("1~100까지의 합 = %d\n",sum);

}

 

i가 100보다 작으면 i를 1증가시키고 here로 점프한다. 일정한 조건이 만족될 때 앞쪽으로 제어를 보냄으로써 반복문과 동일한 효과를 내고 있는 것이다. 물론 i가 100보다 작지 않으면 goto here가 실행되지 않으므로 루프가 종료될 것이다.

goto를 사용한 코드는 일단은 아주 직관적이고 이해하기도 쉽다. 위에서부터 아래로 순서대로 실행하다가 goto를 만나면 지정한 곳으로 점프해 버리면 된다. 그러나 코드가 짧은 경우에는 이해하기 쉽지만 길어지면 오히려 더 이해하기 어려워지고 여러 가지 부작용이 생기기 때문에 요즘은 거의 사용되지 않는다.

우선 goto문은 프로그램의 구조를 엉키게 만든다. 아무곳에서나 제어를 옮길 수 있기 때문에 쓰기는 쉽지만 코드를 유지하기가 무척 어렵다. 여기서 저기로 제어를 옮겨서 따라 가 보면 또 조기로 폴짝 뛰어 가 버리고 또 조기서 다시 다른 곳으로 제어를 옮겨 버린다. 이런 식으로 코드가 개구리처럼 아무곳으로나 점프해 다니면 이 코드를 보는 사람은 물론이고 직접 작성한 사람도 어지간해서는 분석하기가 어렵다. 다음 가상의 코드를 보자.

goto문이 많기 때문에 이리 저리 뛰어 다니느라 정신이 없다. 겨우 레이블 다섯 개 정도로도 저 모양인데 레이블이 수백개 정도 되면 어떻게 되겠는가? 이렇게 얼키고 설킨 코드를 스파게티 소스라고 하는데 마치 스파게티 면발이 꼬여 있는 것처럼 복잡해서 웬만한 체력으로는 이런 코드를 관리하기 어렵다. 여담이지만 사실 스파게티가 꼬여 봐야 얼마나 꼬여 있겠는가? 우리나라 사람이 C를 만들었다면 아마 라면 코드라고 이름을 붙였을 것이다.

또한 goto문은 프로그램의 구조를 해치기 때문에 goto문을 사용한 소스는 이식성과 재사용에 무척 불리하다. 특정 동작을 하는 코드를 다른 프로그램에서 재사용하려면 goto문에 의해 엉켜 있는 실을 다 풀어야 하고 옮긴 후에 다시 그 프로그램에 맞게 연결해야 하기 때문이다. 아무 규칙이나 형식없이 제어를 마음대로 옮길 수 있다보니 부작용이 많다.

이런 여러 가지 이유로 아주 특별한 경우가 하닌 한은 goto문을 사용하지 말 것을 권장하고 있다. goto문이 아니면 도저히 해결할 수 없는 그런 문제는 없다. goto문이 없어도 for, while, switch같은 제어문으로 필요한 모든 구조를 다 만들 수 있다는 것이 이미 수학적으로 증명되어 있다. 특별한 경우를 제외하고는 goto문을 쓰지 말아야 하며 특히 처음 프로그램에 입문하는 사람은 의식적으로 goto문을 쓰지 않는 연습을 해야 한다.

그렇다면 이렇게 악명높은 goto문을 C언어는 왜 지원하는 것일까? 뿐만 아니라 비교적 최신 언어인 자바나 C#에도 여전히 goto문은 존재하는데 이 명령이 비록 불필요하기는 하지만 가끔 아주 효율적으로 사용할 곳이 남아 있기 때문이다. 시스템 프로그램이나 디바이스 드라이버같이 이식성이나 유지의 편의성, 가독성보다는 무엇보다 성능을 최우선으로 하는 곳에는 여전히 goto가 사용된다. 왜냐하면 goto는 컴퓨터가 알아들을 수 있는 유일한 제어문이며 또한 컴퓨터가 가장 쉽게 실행할 수 있는 제어문이기 때문이다. 컴퓨터는 for나 while같은 건 모른다. 오로지 정해진 번지로 점프하는 것만 가능하며 컴파일러가 for, while을 기계가 알아들을 수 있는 점프문으로 바꿔주는 것이다.