GOTO

혹시 검색 광고 업체 고투닷컴을 찾고 계셨나요?

1 개요

프로그래밍에서 어느 특정 줄 번호나 레이블로 건너뛰거나 돌아갈 때 쓰는 명령이다. 웜홀같은 개념이라고 보면 된다.

프로그램의 흐름을 바꾸는 기본적인 명령으로, 여러 고급 언어에서 공통적으로 사용되는 명령이다. 다만, 모든 고급 언어에 이 기능이 있는 것은 아니다. Java처럼 예약어로만 존재하고 기능이 없는 경우도 존재한다. 그 이유가 궁금하면 이 글을 끝까지 읽어보자.

2 예제

BASIC에서의 사용 예를 들면 다음과 같다.

10 PRINT "내가 고투라니!"
20 GOTO 40
30 PRINT "이보시오 의사양반!"
40 PRINT "이게 무슨 소리야!"
50 END

이를 실행하면 중간에 30번 행이 있지만 20번 행에서 40번 행으로 건너뛴다. 그래서 다음과 같이 나온다.

내가 고투라니!
이게 무슨 소리야!

3 GOTO문의 해로움

GOTO Statement Considered Harmful [1] - Edsger W. Dijkstra

고급 언어에서 GOTO문은 많은 커뮤니티에서 터부시되는 구문이다. 그 이유는 이게 너무 많이 쓰이다 보면 구조가 무너지고 코드가 황폐화되면서 이게 어째 실행은 잘 되긴 되는데 코드를 짠 프로그래머 자신도 "이게 뭥미?"하는 소리가 절로 나오며 읽고 유지보수하기가 힘들어지는 지경에 이르게 된다. 이러한 상태로 된 코드를 '스파게티 코드'라고 한다. 이런 스파게티 스타일을 반대하고 구조적 프로그래밍을 주창한 네덜란드의 컴퓨터 과학자 에츠허르 다익스트라(Edsger Wybe Dijkstra)는 GOTO문의 사용이 프로그램의 정확성 분석과 증명 등의 측면에 해가 된다고 한 바 있다. 실제 프로그래밍할 때도 GOTO문을 남용하면 디버깅 불가+기능 추가 난해+다른 사람의 욕 처먹기+왜 이런 코드를 짰지 하고 생각하는 자괴감이 드는 사단 콤보가 일어날 수 있다.

4 GOTO문의 이로움

int sock_create_lite(int family, int type, int protocol, struct socket **res)
{
err = security_socket_create(family, type, protocol, 1);
if (err)
goto out;
sock = sock_alloc();
if (!sock) {
err = -ENOMEM;
goto out;
}
sock->type = type;
err = security_socket_post_create(sock, family, type, protocol, 1);
if (err)
goto out_release;
out:
*res = sock;
return err;
out_release:
sock_release(sock);
sock = NULL;
goto out;
}

[2]
GOTO를 터부시한 사람들은 goto의 사용에 놀라고 출처에 또 한번 놀란다
GOTO문의 남용은 소스코드의 이해를 어렵게 만들지만, 적절한 사용은 오히려 소스코드의 가독성과 명료성을 높이는 경우가 있다. 가령 다중 반복문에서의 탈출[3], 에러에 대한 예외 처리[4] 등 일부 작업에 한해서는 GOTO문을 사용하는 경우가 더 명료한 경우도 있다. 다만 위의 경우라도 로직 레벨에서의 탈출이나 함수화 시킨 후에 return등을 이용하는 등 GOTO문을 쓰지 않기를 권고하는 경우도 많다.
대표적인 예시로 리눅스 커널 소스코드를 까봐도 심심찮게 GOTO문을 발견할 수 있다.[5] 터부시 되기에는 나름대로 쓰임새가 있는 것도 사실. 그러나 초보자에게는 많은 경우에 일종의 금기로써 가르친다. GOTO문이 유용한 경우는 어디까지나 특수한 케이스이고 잘못 사용했을 경우의 어디서부터 손대야할지 모르는 스파게티를 만들어버리는데다가 초보자의 경우 특히 가능성이 높기 때문(..) C언어보다 고수준 언어를 사용한다면 예외처리는 exception(try-catch)으로, C++같이 리소스 해제가 수동이지만 RAII를 지원하는 경우는 RAII를 사용하자. 용법은 같으면서 가독성은 증가한다. 다만 그런거 없는 C언어에서는 예외처리와 동적 리소스 해체에 goto를 주로 사용한다.

사실 이 GOTO문은 프로그래밍 언어의 시초격이라 할 수 있는 어셈블리어의 산물이다. 어셈블리어에서는 프로그램의 흐름을 제어할 수 있는 구문이 Jump[6] 계열의 명령어밖에 없는데, 이는 무조건적으로 혹은 특정 조건을 만족하면 명령어에서 지시하는 프로그램 카운터로 이동하는 구문이다. 고급 언어로 쓰인 코드도 컴파일해서 어셈블리 소스를 열어보면 전부 GOTO문의 반복형으로 되어있다.[7]

5 그 외

  • BASIC에는 GOTO문 외에도 GOTO문과 비슷한 GOSUB문이 있다.
  • PHP에는 없다가 5.3 버전에서 생겼다.
  • Lua에는 5.2부터, LuaJIT에서는 2.0부터 있는데, 특이한 점은 타 언어의 Continue가 존재하지 않는다.
  • if와 goto만 있어도 for, while, switch등을 전부 대체할 수 있다.
  1. 이 GOTO문의 사용이 해가 된다고 지적한 서한의 제목이 'Go to Statement Considered Harmful'(GOTO문의 해로움)이였는데, 이 '... Considered Harmful'라는 어구가 컬트적 인기를 끌어서 컴퓨터 과학 계열에서 어떤 것에 대한 비판을 할때 자주 쓰이는 어구가 되었다(..) . 예를 들어서 'Wiki Neet Considered Harmful' 이런식으로. 참고로 위 서한에 대한 비평으로 ' 'GOTO Statement Considered Harmful' Considered Harmful'('GOTO문의 해로움'의 해로움)이 있었고, 다시 이것에 대한 반응으로 도널드 무어 등은 ' 'GOTO Statement Considered Harmful' Considered Harmful' Considered Harmful? (' 'GOTO문의 해로움'의 해로움'의 해로움?)을 보냈다. 고만해 미친놈들아
  2. 소켓 인터페이스 구현(linux/net/socket.c:1027-1054) 중 발췌. (GPL 라이센스 및 커밋 3c435c)
  3. 자바 등 일부 고급 언어의 경우 GOTO문 외에 다중 반복문을 탈출하는 기능을 제공하긴 한다. C언어는 그런 거 없다.
  4. 에러가 발생했을 때는 에러 코드 및 에러 메시지를 출력한 후에 프로그램을 그 자리에서 종료시켜야 하는 경우가 많다. 계속 실행시켰다가는 에러가 연속적으로 발생하거나 예기치 못한 결과가 나올 수도 있기 때문이다. 이때 goto 문은 프로그램의 가장 끝줄로 점프시키는 용도로도 사용할 수 있다. 위의 소스코드도 에러 예외처리로 GOTO를 사용한 예이다.
  5. 리누스 토르발스는 대표적인 GOTO문 옹호자 중의 한 명이다.
  6. 아키텍처에 따라 Branch로 쓰기도 함
  7. 어셈블리 프로그래밍에 입문하는 경우는 일부러 반복문을 GOTO식으로 고쳐서 쓰는 연습을 하기도 한다