22. 함수 만들기 1 - (defun) 1
목표
함수를 만드는 함수인 (defun)을 알아봅시다
함수란
그동안 계속 써왔던 (getpoint), (if)와 같이, 무언가 기능을 실행하는 애들을 함수라고 합니다. 위 함수들은 오토리습에 이미 정의(등록) 되어 있는 기본함수들이었습니다.
하지만 자기가 원하는 함수를 직접 만들어 쓸 수도 있습니다. 함수를 정의(등록)할 때는 (defun)이라는 함수를 사용합니다. defun은 define function(함수를 정의해라)의 줄임말입니다. (defun)함수는 아래와 같은 형식으로 사용합니다
1
2
3
(defun 함수명 (지역변수지정부)
함수실행코드들
)
이렇게 정의(등록)한 함수는, 그동안 사용했던 것과 마찬가지로 (함수명 인자1 인자2 ...)형식으로 쓸 수 있습니다.
지역변수가 없는 함수
먼저 안녕하세요!만을 출력하는 간단한 함수를 하나 만들어 봅시다. 아래 코드를 복사해서 명령어 창에서 실행 해 주세요
1
2
3
4
(defun sayHi ()
(princ "\n안녕하세요!")
(princ)
)
함수명은
sayhi이며,지역변수지정부에 아무것도 적지 않았으므로, 아무 인자도 받지 않는 함수입니다.
이제 도면에 (sayhi)라는 함수가 정의(등록)되었습니다. 아래와 같이 함수를 사용 해 봅시다.
1
(sayhi)
지역변수가 있는 함수
지역변수지정부
지역변수라는것은, 해당 함수가 시작될 때 생성되었다가 함수가 끝날때는 삭제되는 변수를 말합니다. 함수명 다음에 오는 (지역변수지정부)에서, 함수 내부에서만 사용 할 지역변수들을 지정할 수 있습니다.
지역변수에는 함수를 호출(사용)시에 꼭 넣어줘야 하는 인자도 포함됩니다.
(지역변수지정부)는 가운데 /를 기준으로, 왼쪽은 함수 호출(사용)시 넣어야 할 인자들을, 오른쪽은 그 외에 추가로 함수 내부에서만 사용할 변수들을 지정합니다. 여기서 주의 할 점은 /는 양 옆으로 어느것과도 붙어 있어서는 안 됩니다.
함수 외부에서 사용하지 않을 변수는 반드시 지역변수지정부에 추가시켜 줘야 합니다.(이유는 아래에 적겠습니다.)
예를 들어서 인자가 1개 필요하면서, 추가로 함수 내부에서만 사용할 변수가 2개인 함수는 아래와 같이 만들 수 있습니다.
1
2
3
(defun 함수명 (인자1 / 지역변수1 지역변수2)
함수실행코드들
)
여기서
인자1과/, 그리고/와지역변수1사이는 반드시 떨어져 있어야 합니다. 만약 붙어버린다면, 오토리습은/를 인식하지 못하고,인자1/또는/지역변수1을 변수라고 생각합니다. 왜냐하면 오토리습에서는 변수명에/를 포함한 특수문자를 사용할 수 있기 때문입니다. 그렇게 되면,지역변수지정부에/가 없으므로 오토리습은 이 함수를 3개의 인자를 가진 함수로 생각합니다.
1 2 3 (defun function1 (인자1 /지역변수1 지역변수2)) ; <- 함수호출시 인자 3개를 넣지 않으면 오류발생 ... )
만약 함수 호출시 필요한 인자만 있고, 추가적인 지역변수가 없는 함수에서는 /를 생략해도 됩니다.(있어도 상관없습니다.)
1
2
3
(defun 함수명 (인자1)
함수실행코드들
)
만약 함수 호출시 필요한 인자가 없고 지역변수들만 있는 함수에서는 /를 생략해서는 안 됩니다(생략하면 전부 인자들로 취급됩니다.)
1
2
3
(defun 함수명 ( / 지역변수1 지역변수2)
함수실행코드들
)
인자가 없는 함수에서는
/과 그 앞의(사이에 반드시 공백을 추가해야 합니다. 만약(/처럼 붙어버리면, 오토리습은 앞에서 다루었던 나눗셈함수인(/)로 생각하게 됩니다.
1 2 3 (defun function1 (/ 지역변수1 지역변수2)) ; <- 오류발생 ... )
예시
정수 2개를 입력받아서 그 합을 보여주는 함수를 한번 만들어 봅시다. 아래 코드를 복사해서 명령어 창에서 실행 해 주세요
1
2
3
4
5
(defun add (num1 num2 / sum)
(setq sum (+ num1 num2))
(princ (strcat (itoa num1) " + " (itoa num2) " = " (itoa sum) "입니다."))
(princ)
)
- 이 함수의
지역변수지정부가(num1 num2 / sum)이므로, 이 함수를 사용하려면num1과num2에 해당하는 2개의 인자를 넣어야 하며,num1,num2,sum세 변수는 이 함수가 종료되면 사라집니다.
다시한번 말씀드리지만,
/는 양 옆 누구와도 붙어있어서는 안 됩니다.
이제 위 함수가 도면에 등록되었으니, 한번 사용 해 봅시다. 들어갈 숫자는 마음대로 변경해도 좋습니다.
1
(add 5 7)
- 우리가 정의한
(add)함수는num1과num22개의 정수를 인자로 받는 함수입니다. 따라서(add)함수를 사용할 때는 정수 2개를 인자로 넣어줘야 합니다.- 이렇게 호출한
(add)함수에서는 첫번째 위치한num1에는5가, 두번째 위치한num2에는7이 들어갑니다. 마치(setq num1 5)와(setq num2 7)을 한 것 처럼요. 그 후에는(add)함수 내부의 코드들을 실행하게 됩니다.
지역변수를 선언해야 하는 이유
지역변수지정부로 굳이 해당함수 안에서만 사용 될 변수들을 지정 해 주는 이유가 뭘까요?
오토리습에서는 변수를 생성하면 기본적으로 다른 모든곳에서 그 변수를 사용할 수 있게됩니다. 이를 전역(Global)변수라고 합니다. 하지만, 만약 다른 함수에서 같은 변수명을 사용한다면 문제가 될 수 있습니다.
다음의 경우를 한번 봐 봅시다.
1
2
3
4
5
6
7
8
9
10
11
12
(defun fun1 () ; 함수 fun1 정의
(setq num 3) ;5
) ;6
(defun fun2 () ; 함수 fun2 정의
(setq num 5) ;3
(fun1) ;4
) ;7
(setq num 1);1
(fun2) ;2
(princ num) ;8
- 먼저
(fun1)을 정의합니다. 이 함수에서는num에 3을 넣는 내용이 들어있습니다.- 다음으로
(fun2)를 정의합니다. 이 함수에서는 먼저num에 5를 넣은 후,(fun1)함수를 호출합니다. 여기까지는 함수 정의부입니다.- 이제부터는 실제로 코드를 실행합니다.
num에 1을 넣습니다.- (
fun2)함수를 호출합니다.- 마지막으로
num에 담긴 값을 출력합니다.
그렇다면 과연 명령어창에 출력되는 값은 5일까요? 3일까요? 정답은 3입니다. 왜냐하면 다음과 같이 실행되기 때문입니다.
num에 1 넣음(fun2)호출num에 5 넣음(fun1)호출num에 3 넣음(fun1)종료(fun2)종료num의 값인 3 출력
이는 fun1과 fun2 모두 num이라는 동일한 이름의 변수를 사용하기 때문에 발생하는 문제입니다.
이를 방지하려면 함수 내부에서만 사용되었다 사라지는 지역변수를 만들어야겠죠. 전역이 아닌 함수 내부에서만 존재하기 때문에 지역(Local)변수라고 합니다.
이제 각 함수의 num변수를 지역변수로 등록 해 봅시다.
1
2
3
4
5
6
7
8
9
10
11
12
(defun fun1 ( / num) ; num을 지역변수로 등록
(setq num 3) ;5
) ;6
(defun fun2 ( / num) ; num을 지역변수로 등록
(setq num 5) ;3
(fun1) ;4
) ;7
(setq num 1);1
(fun2) ;2
(princ num) ;8
이제는 다음과 같이 실행됩니다.
num(전역변수)에 1 넣음- (
fun2)호출 num((fun2)지역변수)에 5를 넣음(fun1)호출num((fun1)지역변수)에 3을 넣음(fun1)종료 :num((fun1)지역변수) 삭제(fun2)종료 :num((fun2)지역변수) 삭제num(전역변수)의 값인1출력
(fun1)과 (fun2) 내부의 num은 지역변수로 지정했기 때문에, 각 함수가 종료될 때 지역변수인 num도 같이 삭제됩니다.
이렇게 외부 함수를 실행하더라도 각 변수는 해당 함수 내에서만 사용 가능하고, 함수 외부에서는 변경이 불가능하게 만들어야, 예상하지 못한 결과를 막을 수 있습니다.
따라서 일부러 전역변수로 만들고 싶은 경우가 아닌이상, 항상 함수를 정의(생성)할 때는 함수 내부에서 사용할 변수들은 지역변수지정부에 등록하여 사용해야 합니다.
%201-1.gif)