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
과num2
2개의 정수를 인자로 받는 함수입니다. 따라서(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
도 같이 삭제됩니다.
이렇게 외부 함수를 실행하더라도 각 변수는 해당 함수 내에서만 사용 가능하고, 함수 외부에서는 변경이 불가능하게 만들어야, 예상하지 못한 결과를 막을 수 있습니다.
따라서 일부러 전역변수로 만들고 싶은 경우가 아닌이상, 항상 함수를 정의(생성)할 때는 함수 내부에서 사용할 변수들은 지역변수지정부
에 등록하여 사용해야 합니다.