8. 함수
함수는 동일한 기능 또는 목적을 가진 코드의 모음이다.
▼ CPP 함수 예제
#include <cstdio>
void PrintHello()
{
printf("Hello\n");
}
int main()
{
PrintHello();
return (0);
}
앞선 괄호 편에서 C언어를 개발한 데니스 리치가 같은 기능 또는 목적을 가진 코드를 위해서 중괄호를 사용한다고 언급한 바 있다.
그렇기 때문에 C언어의 언어철학에서는 코드의 길이가 길던 짧던 웬만하면 함수화 하는 것을 이상적으로 생각한다.
CPP은 C언어에 비해 훨씬 객체지향적으로 코드를 설계할 수 있기 때문에 함수 화하는 것은 여전히 중요하다.
함수는 버릇적으로 만들만큼 연습하는 게 중요하다고 한다.
마냥 무작정 함수의 갯수가 늘리는 게 중요한 것이 아니라 같은 기능의 코드들을 얼마나 잘 파악하는지가 중요하다.
함수를 만드는 데 걸리는 시간 중 8할은 이름 짓기다.
▼ 아마 세상에서 제일 많이 사용되었을 함수 이름 foo
void foo(char* bar) {
printf("%s", bar);
}
정말 유명하지만 바람직한 함수 명명 예제는 또 아니다.
왜 굳이 foo-bar라고 하는 지 여러 속설이 있다.
가장 흔하게 받아들여지는 속설은 세계 2차 대전 당시의 미군 속어(FUBAR : Fucked Up Beyond All Repair)에서 비롯되었다는 것이다.
그 후로는 프로그래머들끼리 암묵적인 밈(meme)으로 사용해왔다고 한다.
외국 포럼의 영어권 개발자들 역시 서로 왜 이걸 굳이 쓰더라? 하는 걸 보면 일종의 카페의 맥북 같은 존재였던 걸로 보인다.
(쓰면 왠지 프로그래머 갠지가 나보여서)
아무튼 어디까지나 밈으로써 편의상으로써 저걸 쓰는 거지 실제 게임 개발에서 저렇게 함수명을 지으면 난리가 날 것이다.
▼ 언제나 팬심이 옳은 건 아니다.
프로그래머1 : 어라? 가장 인접한 적을 찾는 함수가 이상한거 같은데. 프로그래머2님, 함수 명이 뭐에요? 프로그래머2 : ILoveIU요. 프로그래머1 : 뭐요? |
저 정도까지는 아니더라도 실제로 함수명과 함수 기능이 다른 경우도 있다.
어떻게 보면 가장 흔한 실수 중 하나인데 프로그램을 개발하다가 기능이 변경되거나 규모가 커졌을 때 발생한다.
▼ 함수명과 함수 기능은 언제나 일치해야 한다.
#include <cstdio>
void PrintHello()
{
printf("Hi!\n");
}
void PrintHi()
{
printf("Hi\n");
}
int main()
{
PrintHello(); // Not OK
PrintHi(); // OK
return (0);
}
다른 프로그래머가 Hello! 를 출력하고 싶어서 PrintHello()를 사용했는데 Hi! 가 나오는 상황이 발생한다.
이러한 실수는 게임에 치명적인 버그로 돌아오기 때문에 프로그래머는 반드시 함수명과 함수 기능을 일치시켜야 한다.
가장 좋은 연습법은 협업 코드를 많이 짜고, 좋은 게임 코드들을 많이 보는 것 말고는 없다.
그리고 코드 룰에 완전한 룰은 존재하지 않는다.
프로젝트에 따라 팀에 따라 개발자에 따라 다 다른 것이 원래는 맞다.
함수 매개변수와 인자의 차이점
▼ 매개변수와 인자
#include <cstdio>
int Sum(int a, int b) // Parameter
{
return (a + b);
}
int main()
{
int a, b, result;
a = 1;
b = 3;
result = Sum(a, b); // Argument
printf("%d + %d = %d\n", a, b, result);
return (0);
}
한국어로도 영어로도 매개변수(Parameter)와 인자(Argument)라고 나뉘는데 하는 역할은 비슷해 보인다.
실제로는 정의할 때와 호출할 때 부르는 명칭이 다른 것뿐이다.
함수를 정의할 때에 함수에게 필요한 매개체를 정의할 때에는 매개변수라고 말한다.
그래서 다른 프로그래머에게 어떤 기능이 있는 함수를 만들어야 할 때에는 아래와 같이 말하는 게 옳다.
▼ 함수를 선언할 때에는 매개변수
프로그래머1 : int a와 int b를 매개변수로 가지고 더한 값을 반환하는 함수 Sum을 만들어야 해. |
반면 함수를 사용할 때에는 인자라고 말한다.
특정 기능의 함수를 어떻게 호출하는지 물을 때는 인자로 묻는 게 옳다.
▼ 함수를 호출할 때에는 인자
프로그래머1 : 00씨 Sum 함수 어떤 인자가 들어가요? |
물론 요즘 IDE에선 프로그래머가 마우스 커서만 올려도 함수가 어떤 인자를 가지는지 보여준다.
그러나 그런 기능이 없을 때를 가정하면 충분히 그 용어의 차이가 드러난다.
함수의 매개변수명은 함수명만큼 중요하다.
▼ 인자 변수명만 보고도 뭘 원하는지 알아야 한다.
#include <cstdio>
void Print(int num)
{
printf("%d", num);
}
void Print(char *str)
{
printf("%s", str);
}
int main()
{
Print(1);
Print(str);
return (0);
}
함수명과 함수 매개변수명은 서로 상호보완적인 존재다.
앞서 괄호 편에서 소괄호가 가지는 의미에 대해서 간단히 정리했던 걸 기억해보자.
함수명을 작명할 때 매개변수까지 같이 넣는 경우가 많다.
매개변수가 함수를 수식하기 때문에 실제로 함수명에 매개변수가 들어가는 것은 바람직하지 않다고 보는 시선도 적지 않다.
이는 Print라는 함수가 정수와 문자열 말고도 출력할 경우가 많을 수 있다는 가능성이 문제가 된다.
만약 PrintNum, PrintStr 같이 매개변수가 함수명에 들어가면 새 경우가 생길 때마다 매번 새 함수를 만들고 이름을 바꿔줘야 하는 문제가 발생할 수 있기 때문이다.
그래서 출력하는 기능 하나에 함수를 집중하고 매개변수의 이름을 직관적으로 짓는 방법이 선호되곤 한다.
하지만 이 역시 프로젝트나 팀의 성향에 따라 다 달라지기 때문에 본인의 실수를 가장 줄일 수 있는 방법을 찾는 게 좋다.