프날 오토핫키 강좌  v2

⚠ 이 강좌는 오토핫키 v2를 다룹니다

지금 보시는 강좌는 과거 오랜 시간동안 알려진 오토핫키(v1.1)의 차세대 버전인 오토핫키 v2를 다루고 있습니다.
만약 구버전인 '오토핫키 v1.1'의 강좌를 찾으신다면 프날 오토핫키 강좌(https://pnal.kr)를 봐주시면 되지만, 새로 오토핫키를 배우신다면 v2 버전을 배우시는 것을 강력히 추천드립니다.

55. 참조에 의한 호출


함수를 사용할 때 알면 좋은 '값에 의한 호출'과 '참조에 의한 호출'에 대해서 배워봅시다. 지난 강에서 배운 '참조'를 반드시 알아야 이해하기 쉽습니다.

값에 의한 호출

일반적인 경우에, 변수는 그 자체가 아닌 값을 이용합니다. 아래와 같은 스크립트를 보겠습니다.

1a := 1
2Foo(a)
3MsgBox(a)
4
5Foo(param)
6{
7 param := 2
8}
함수 내부에서 값이 바뀌어도 a는 1이다.

함수를 호출할 땐 변수 자체가 아니라 변수의 이 매개변수에 복사됩니다. 그래서 함수 내부에서 매개변수의 값을 바꿔도, 인수로 전달된 변수는 아무런 변화가 없습니다. 위의 예시는 그래서 1이 출력됩니다.

이렇게 변수를 사용하면 일반적으로 그 을 사용합니다. 이것은 우리가 지금까지 써왔던 변수의 당연한 성질입니다. 이렇게 일반적으로 값이 복사되어 매개변수로 전달되는 방식을 값에 의한 호출라고 합니다.

참조에 의한 호출

매개변수에 참조를 전달할 수 있습니다. 즉, 아래와 같은 경우가 있습니다.

1a := 1
2Foo(&a)
3MsgBox(a)
4
5Foo(param)
6{
7 %param% := 2
8}
참조된 변수의 값이 바뀌면?

이 경우엔 아까와 다르게 2가 출력됩니다. 함수 내부에서 값을 바꿨음에도 불구하고, 인수로 전달해준 변수의 값이 변경된 것이죠. 왜 그럴까요? 지난 강에서 배운 참조와 역참조를 떠올려봅시다.

함수의 인수로 &a를 전달했습니다. 한마디로 parama를 참조하고 있다는 것이지요. 참조인 param을 다시 역참조하면 a를 이용할 수 있습니다. 결국 함수 내부에서도 함수 바깥에 있는 a의 값을 변경할 수 있게 되었습니다. 지난 강에서 배웠듯이, a의 참조를 param으로 복사하여 다시 역참조하면 결국 a와 같습니다.

이렇게 인수로 '참조'를 전달해주는 함수 호출 방식을 참조에 의한 호출이라고 합니다.

참조에 의한 호출의 장점

보시다싶이 참조를 인수로 넘겨준다면, 인수로 넘겨준 변수의 값을 함수 내부에서 수정할 수 있습니다. 만약 이것이 불가능했다면 수정한 값을 다시 반환하여 함수 바깥에서 대입해주어야 했을 것입니다. 이런 참조에 의한 호출을 사용하여 얻는 이점이 몇가지 있습니다.

  • 참조에 의한 호출을 이용하면 반환값을 사용하지 않아도 여러 값을 변경할 수 있습니다.
  • 크기가 큰 값을 매개변수로 복사할 필요가 없기 때문에 성능상 이득이 됩니다.

참조에 의한 호출을 사용했던 대표적인 경우가 37강에서 배운 MouseGetPos입니다. MouseGetPos는 현재 마우스 커서의 좌표를 가져와주는 함수로, 아래와 같이 사용했었습니다.

1MouseGetPos(&vx, &vy)
MouseGetPos의 사용 - 참조에 의한 호출

인수에 쓰인 참조 연산자(&)가 보이시나요? 왜 우리는 이 함수에게 참조를 넘겨주었을까요? 바로 "매개변수로 전달된 변수의 값을 함수 내부에서 바꿔주기 위해" 입니다.

위와 같이MouseGetPos를 호출하면, 변수 vxvy에 현재 마우스의 x, y 좌표가 담겼습니다. 즉, (어딘가에 있는) MouseGetPos 함수의 정의에서 인수로 전달된 &vx, &vy를 역참조하여 그 값을 수정해줄 것입니다. 그러면 vx, vy의 값이 수정된 셈이죠. 이해가 되시나요?

함수는 원칙적으로 한 가지 값만 반환할 수 있습니다. return vx, vy 같이 사용할 순 없습니다. 그렇기에, 두 가지 이상의 값을 호출부에게 알려주어야 하는 MouseGetPos 같은 함수는 '참조에 의한 호출'을 이용했습니다. 성공적으로 마우스 커서의 x좌표와 y좌표를 변수에 담아줄 수 있었죠.

또, 참조에 의한 호출을 사용하면 인수로 큰 값을 전달했을 때 그 값을 직접 매개변수로 복사할 필요가 없으므로 성능상 이점을 얻을 수 있습니다. 매개변수로 복사되는 것은 '참조'이지, '값' 자체가 아니기 때문입니다. 어마어마하게 큰 문자열 같은 경우엔 아래와 같이 참조로 전달하는 편이 성능상 좋습니다. 그렇지 않으면 함수를 호출할 때마다 큰 문자열이 매번 함수의 매개변수로 복사될 것입니다.

1hugeString := "문자열 400만자"
2Foo(&hugeString)
3
4Foo(haystack)
5{
6 함수의 본문
7}
참조를 전달하여 성능상 이득을 꾀한 예시

⚠ 참조에 의한 호출의 남용

전역 변수를 남용하면 안되는 이유와 마찬가지로, 참조에 의한 호출을 사용하면 코드의 강건성이 떨어지기 때문에 이를 남용하면 안됩니다. 함수 내부에서 바깥의 값을 자유롭게 수정할 수 있기 때문에, 의도치 않게 값을 변경하는 실수를 저지르기도 하기 때문입니다.

따라서 꼭 필요한 경우(두 개 이상의 값을 수정해야 하는 경우 등)에만 참조에 의한 호출을 사용하세요.

참조 매개변수

지금까지 배운 바로는, 참조를 함수에 넘겨주면 매번 그것을 역참조하여 사용해주어야 했습니다.

1Foo(&bar, &baz)
2
3Foo(param1, param2)
4{
5 %param1% := 2
6 MsgBox(%param2%)
7}
참조에 의한 호출의 구현 - 매개변수를 일일이 역참조했던 예시

그렇지만 만약 함수를 정의할 때 참조만 전달받을 수 있도록 '참조 매개변수'를 지정해준다면, 역참조하지 않아도 참조하는 변수를 바로 이용할 수 있습니다. 매개변수를 받자 마자 자동으로 역참조되는 셈이죠.

함수의 정의에서 매개변수의 앞에 참조 연산자(&)를 붙여주기만 하면 참조 매개변수를 지정할 수 있습니다.

1Foo(&bar, &baz)
2
3Foo(&param1, &param2) ;참조 매개변수로 지정
4{
5 param1 := 2
6 MsgBox(param2)
7}
참조 매개변수의 사용

위의 예시에선 param1param2 모두 매개변수 앞에 & 연산자를 써서 참조 매개변수를 지정해주었습니다. 따라서 역참조해주지 않고 매개변수를 이용하는 모습을 볼 수 있습니다. 참조 매개변수는 받는 순간 역참조 된 셈으로, 일일이 역참조 해줄 필요가 없습니다.

즉, 여러분은 역참조 연산자를 쓸 일이 거의 없습니다. 참조를 사용하는 가장 큰 이유는 '참조에 의한 호출'을 하기 위함인데, 참조에 의한 호출에선 매개변수를 참조 매개변수로 지정해줄 수 있으니까요. 결국 위의 예제처럼 간단하게 사용하시면 됩니다. 일일이 역참조 하며 쓰지 마세요!

질문하러 가기