매크로 함수
#include <iostream> #define SQUARE(x) x * x using namespace std; int main(){ cout << SQUARE(3) << '\n'; return 0; }
매크로 함수는 다음과 같이 정의한다.
#define (함수 이름) (치환할 것)
위의 코드에서 SQUARE라는 함수의 내용을 x * x로 치환한다는 것이다. 만약 위의 매크로 함수와 같은 역할을 하는 SQUARE 라는 함수가 존재할 때, 컴파일러는 해당 함수를 호출해서 x에 3을 넣고 3 * 3을 계산할텐데, 매크로 함수는 함수 호출하는 과정이 필요 없이 컴파일 전에 연산을 처리해버린다.
여기서 생각해봐야 할 문제가 생기는데, 만약 SQUARE(3 + 1)을 넣으면 어떻게 될까? 3 + 1을 그대로 SQUARE에 넣어보면 (우리가 의도한 것을 생각하지 말고 그대로 넣어보자) 3 + 1 * 3 + 1 이라는 식이 나올 것이다. 실제로 매크로 함수는 저 계산 결과를 출력할 것이다. 매크로 함수는 위에서 말했듯이 변수가 치환할 값을 의미한다. 즉, "x = 3 + 1 이므로 (3 + 1) * (3 + 1) 의 결과가 나올 것이다" 라는 예상과는 달리 x의 값을 3 + 1로 어떤 첨가도 없이 그대로 치환해버리는 것이다.
그렇다면 우리가 의도한 내용이 되려면 어떻게 해야 할까? 위의 식 대신 아래와 같은 식을 넣으면 될 것이다.
SQUARE(x) (x) * (x)
컴파일 전에 연산을 처리하기 때문에 함수의 호출 과정이 생략되어 일반적인 함수보다 속도가 빠르며 기본적으로 사용하기 편하다는 장점이 있는 반면에, 위와 같이 괄호 하나에 따라 연산의 결과가 완전히 달라져 실수하기가 쉽고 함수 내용이 조금만 복잡해지면 매크로 함수를 사용하기 어렵다는 단점이 있다.
인라인 함수는 우리가 기본적인 함수를 작성하는 것과 거의 똑같은데, 앞에 inline이라는 키워드가 붙었다는 것이 다르다. 그렇다면 일반적인 함수와는 뭐가 다른가? 일반적인 함수는 컴파일러가 main에서 해당 함수를 호출하는 과정이 발생하는데, 이 때 단순히 main 함수에 그 함수의 내용을 다 때려박는 것보다 시간이 당연히 더 들게 된다. 쉽게 생각해서 집에서 공부하는 시간과, 집에서 카페로 가서 공부하는 시간은 공부시간은 같더라도 이동하는 시간이 추가된 것처럼 말이다.
인라인 함수는 함수를 호출하는 과정을 거칠 필요없이 방금 말한 "main 함수에 함수의 내용을 다 때려박는" 것과 같다. 즉, cout << SQUARE(3) 과 cout << 3 * 3 이 완전 같은게 된다. 심지어 위의 매크로 함수에서는 3 + 1을 넣을 때 3 + 1 * 3 + 1의 연산을 처리했지만, 인라인 함수는 이것보단 좀 똑똑하게 함수의 매개변수에 3 + 1을 넣은 것과 같은 방식으로 처리해준다. 그렇다면 뭐하러 매크로 함수를 사용하는 걸까? 인라인 함수가 완전히 매크로 함수의 상위호환처럼 보이는데.
즉 매크로 함수는 자료형을 선언하지 않아 자료형에 의존적이지 않게 되므로
SQUARE((12) * (12)) 는 int형을 호출하며, SQUARE((3.14) * (3.14))는 double형을 호출하게 될 것이다.
반면에 인라인 함수는 int 자료형으로 선언되었으므로 결과값도 int형으로 반환될 것이다. 따라서 매크로 함수와는 다르게 3.14와 같은 double형을 집어넣었을 때 0.14라는 데이터가 손실되어 9라는 결과값이 나오게 될 것이다. 대신 매크로 함수와 같은 방식으로 처리하게 하고 싶으면 자료형에 따라 함수를 오버로딩해주면 된다. (하지만 이렇게 할거면 뭐하러 인라인을 사용하는가. 같은 내용이라면 매크로 함수를 쓰고 말지)
그렇다면 이런 경우는 매크로 함수를 사용할 수 밖에 없는 것인가? 라고 한다면 그건 또 아니다. 템플릿을 사용하면 된다.
이렇게 하면 의도한 자료형으로 출력하게 만들 수 있다.
인라인 함수
#include <iostream> using namespace std; inline int SQUARE(int x){ return x * x; } int main(){ cout << SQUARE(3) << '\n'; return 0; }
인라인 함수는 우리가 기본적인 함수를 작성하는 것과 거의 똑같은데, 앞에 inline이라는 키워드가 붙었다는 것이 다르다. 그렇다면 일반적인 함수와는 뭐가 다른가? 일반적인 함수는 컴파일러가 main에서 해당 함수를 호출하는 과정이 발생하는데, 이 때 단순히 main 함수에 그 함수의 내용을 다 때려박는 것보다 시간이 당연히 더 들게 된다. 쉽게 생각해서 집에서 공부하는 시간과, 집에서 카페로 가서 공부하는 시간은 공부시간은 같더라도 이동하는 시간이 추가된 것처럼 말이다.
인라인 함수는 함수를 호출하는 과정을 거칠 필요없이 방금 말한 "main 함수에 함수의 내용을 다 때려박는" 것과 같다. 즉, cout << SQUARE(3) 과 cout << 3 * 3 이 완전 같은게 된다. 심지어 위의 매크로 함수에서는 3 + 1을 넣을 때 3 + 1 * 3 + 1의 연산을 처리했지만, 인라인 함수는 이것보단 좀 똑똑하게 함수의 매개변수에 3 + 1을 넣은 것과 같은 방식으로 처리해준다. 그렇다면 뭐하러 매크로 함수를 사용하는 걸까? 인라인 함수가 완전히 매크로 함수의 상위호환처럼 보이는데.
인라인 함수와 매크로 함수의 차이점
매크로 함수를 다시 자세히 보고 오자. 변수에 자료형을 넣었는가? 매크로 함수는 자료형이 없이 그냥 치환할 값을 선언하기만 했다. 반면에 인라인 함수는 int 형이라는 자료형을 가지고 있다.즉 매크로 함수는 자료형을 선언하지 않아 자료형에 의존적이지 않게 되므로
SQUARE((12) * (12)) 는 int형을 호출하며, SQUARE((3.14) * (3.14))는 double형을 호출하게 될 것이다.
반면에 인라인 함수는 int 자료형으로 선언되었으므로 결과값도 int형으로 반환될 것이다. 따라서 매크로 함수와는 다르게 3.14와 같은 double형을 집어넣었을 때 0.14라는 데이터가 손실되어 9라는 결과값이 나오게 될 것이다. 대신 매크로 함수와 같은 방식으로 처리하게 하고 싶으면 자료형에 따라 함수를 오버로딩해주면 된다. (하지만 이렇게 할거면 뭐하러 인라인을 사용하는가. 같은 내용이라면 매크로 함수를 쓰고 말지)
그렇다면 이런 경우는 매크로 함수를 사용할 수 밖에 없는 것인가? 라고 한다면 그건 또 아니다. 템플릿을 사용하면 된다.
#include <iostream> using namespace std; template <typename T> inline T SQUARE(T x){ return x * x; } int main(){ cout << SQUARE(3) << '\n'; cout << SQUARE(3.14) << '\n'; }
이렇게 하면 의도한 자료형으로 출력하게 만들 수 있다.
댓글
댓글 쓰기