Post List

2017/12/19

C++__inline function (인라인 함수) 란?

오늘은 인라인 함수에 대해서 알아보겠습니다. 

인라인 함수
 - 인라인이라는 의미는 코드 라인 자체가 안으로 들어간다는 뜻으로 즉, 함수의 메모리주소로 바인딩 되어 실행되는것이 아니라, 호출하는 코드  함수 내용의 코드로 삽입되는 함수를 말합니다.
인라인 함수는 프로그램의 코드들 가운데 컴파일된 함수 코드가 삽입이 됩니다.
이는 컴파일러에 의해 해당 인라인 함수가 함수 코드로 대체됨을 뜻하는데요, 이렇듯 인라인 함수를 사용하면, 프로그램은 해당 코드를 수행하기 위해 위의 일반 함수 수행처럼 메모리에 있는 함수의 주소를 찾아 점프할 필요가 없어지게 되어, 일반 함수보다 약간이나마 빠른 수행 속도를 갖을 수 있습니다. 

그러나 만약 크기가 큰 코드를 가진 함수를 인라인 함수로 사용하고, 10번을 호출게 된다면, 해당 프로그램 코드 사이에 10개의 복사본을 갖게 됨으로써, 메모리 사용면에서 좋지 않을 수 있습니다.

인라인 함수를 사용하여 효율적인 이점을 내기 위해서는 다음과 같은 특징을 알고 사용하셔야됩니다.

첫번째는, 크기가 작은 함수를 인라인 함수로 사용해야 합니다.
 - 함수 호출 비용이 절약되고, 짧은 인라인 함수는 함수 호출문에 대해 만들어지는 코드보다 목적 코다가 작아질 수 있습니다. 그리고 캐시 적중율이 높아집니다.

두번째는 코드 길이가 긴 인라인 함수는 사용하지 말아야합니다.
그 이유는 코드가 긴 인라인 함수를 남용하게 되면, 컴파일 시에 코드 대체로 인한 목적 코드의 크기가 
증가할 수 있기 때문입니다.

세번째는 가상함수를 인라인 함수로 만들지 말자입니다.
가상함수는 컴파일 시간이 아닌 런타임에 결정되기 때문에 컴파일시에 코드 대체되는 인라인 함수는 사용할 수
없기 때문입니다.

코드로 한번 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
inline void PrintText(void)
{
    cout << "Hello, World" << endl;
}
int main()
{
    PrintText();
    return 0;
}
cs
인라인 함수는 함수앞에 'inline' 키워드를 붙여주면 됩니다.
main함수에서 PrintText()함수를 호출하는 코드이지만 실질적으로 

1
2
3
4
5
6
7
int main()
{
    cout << "Hello, World" << endl;
    return 0;
}
cs
위 코드와 같이 함수호출구문(PrintText())이 함수의 구현부로 삽입되는 방식입니다.

다시 말씀드리자면 인라인 함수는 성능 향상을 위한 것입니다. 물론 이렇게 바꿈으로써 실행 코드가 커진다는 단점이 있습니다. 따라서 인라인 함수는 코드는 작지만 자주 호출되지 않는 경우에 주로 사용하는 것이 좋을꺼같은 생각입니다.

한가지 더 짚고 넘어갈 부분은 인라인함수는 #define 매크로와 기능이 유사합니다. 하지만 매크로 함수보다 인라인 함수의 이점이 많다보니 deine보다 inline함수를 사용하는것을 더 선호합니다.

첫번째로, 인라인 함수의 전달인자에 데이터형을 체크할 수 있습니다. 매크로 기능을 활용할 경우에는 매게변수와 리턴값의 데이터 타입을 정확히 명시할 수 없습니다.

두번째는 매크로가 갖는 부작용 없이 일반 함수처럼 사용이 가능합니다. 매크로를 사용시에 increment등으로 변수를 넘겨줄 경우 일반적으로 함수를 사용할 때와는 다른 값을 얻게 되는 경우가 많습니다. 

세번째로, 디버깅이 가능합니다. 즉, 현재 변수에 어떤 값이 들어가 있는지 알 수 있죠.


그리고 컴파일러에 따라 함수를 인라인화 할것인지 일반함수로 취급할것인지 판별되는 경우도 있습니다.
inline 키워드를 붙이지 않아도 함수의 크기가 작다면 inline되는 경우도 있고, 
inline키워드를 사용했지만 함수의 크기가 큰 경우 일반함수로 취급되는 경우도 있습니다.

마지막으로 함수가 inline화 되지 못하는 경우에 대해서 알아보겠습니다.
첫번째로는, 가변인자를 가진 함수입니다. 몇개의 인자를 가질 지 컴파일러는 알 수 없으므로, 인라인화가 이루어지지 않습니다.
두번째는, 함수 포인터입니다. 함수 포인터의 경우 문법상 같은 시그니쳐의 함수만 전달될 수 있으나, 같은 시그니쳐의 함수가 있을 때 정확히 어떤 함수가 호출되는지 컴파일러는 식별할 수 없습니다. 그래서 컴파일타임에 결정되는 인라인함수에 적합하지 않답니다.
세번째는, 가상함수 입니다. 가상함수는 부모의 함수를 자식 클래스에 재정의(오버라이딩)된 함수입니다. 가상함수는 포인터 타입이 아니라 객체 타입으로 재정의된 함수가 호출되기 때문에 컴파일타임에 알 수 없습니다.
그래서 가상함수 또한 인라인화 될 수 없지요.
네번째는 재귀함수입니다. 재귀함수는 함수의 깊이를 알 수 없고, 재귀 함수가 인라인화 된다 하였을때도
코드의 크기가 방대질 수 있기 때문에 인라인화하지 않는것을 추천합니다.

이 외에도 몇가지 사항들있지만, 많이 사용되는 문법에 대해서만 소개했습니다.