C++ 에서 함수를 호출하는데 있어서는 어느 정도 댓가가 따른다. 함수를 호출하기 직전에 기존 정보를 저장하고 인자를 넘겨주고 실행 순서를 바꾼 후 함수의 수행이 끝나면 사용한 메모리를 정리하고 반환값을 받는다. 즉 함수 호출 전후에 필수적으로 수행해야하고 메모리와 시간을 요하는 작업들이 있는 것이다. PC에서 수행되는 프로그램을 작성할 때에는 이러한 오버헤드는 무시할 수 있을 것이다. 하지만 아두이노와 같은 메모리나 성능이 매우 제약된 프로세서를 프로그래밍할 경우에는 무시 못할 성능 저하 요인이 될 수도 있다.


 C++의 인라인(inline)함수는 함수의 길이가 매우 짧을 경우에 효율을 높이기 위해서 도입된 방법으로서 함수의 선언부 앞에 inline 이라는 키워드로 구현된다. 이전의  코드로 예를 들면 다음과 같다.

inline boolean Button::isPushed() {
   return (digitalRead(_pin) == LOW)? true:false;
}


컴파일러는 인라인 함수를 호출하는 곳에 인라인 함수의 코드를 그대로 삽입하여 함수의 호출이 일어나지 않도록 한다. 이렇게 되면 함수를 호출할 때 드는 비용이 없어지기 때문에 속도가 더 올라간다. 반대 급부로 프로그램의 길이는 더 길어지게 된다.

 다른 객체지향 언어(JAVA, C# 등등)도 마찬가지지만 C++도 비교적 작은 크기의 함수를 많이 사용한다. 대표적인 것이 멤버 변수를 접근하는 getter/setter 함수인데 이러한 사용 빈도가 높고 크기가 작은 함수들을 inline으로 정의해 놓으면 더 높은 실행 효율을 얻을 수 있다.


 함수를 inline으로 설정했다고 모두 코드를 치환하는 것은 아니고 컴파일러에 따라서 동작 방식이 다르다. 자기 자신을 호출하는 재귀함수나 반복문, switch문 등이 포함된 함수는 inline으로 지정했다고 하더라도 컴파일러에 의해서 인라인 선언이 무시될 수도 있다. 또한 생성자를 포함하여 모든 멤버 함수가 인라인으로 선언될 수 있다. 이전 포스트의 Button클래스의 멤버 함수를 인라인 함수로 지정하면 다음과 같다.

class Button {
   public:
     Button(byte, boolean); // 생성자
     boolean isPushed(); // 버튼이 눌렸다면 true를 반환하는 멤버 함수
   private:
     byte _pin; // 연결된 핀
     boolean _internalPullup; //내부에 풀업이 되었는가
};
// 생성자의 구현
inline Button::Button(byte pin, boolean internalPullUp = true) {
   _pin = pin;
   _internalPullup = internalPullUp;
   if (_internalPullup)
       pinMode(_pin, INPUT_PULLUP);
   else
   pinMode(_pin, INPUT);
}
// 멤버 함수의 구현
inline boolean Button::isPushed() {
   return (digitalRead(_pin) == LOW)? true:false;
}

 멤버 함수의 크기가 작을 경우 클래스의 선언부에 바로 함수를 구현해도 무방하다. 즉, 위 예의 isPushed() 함수를 다음과 같이 클래스의 선언부에 바로 구현해도 된다.

class Button {
   public:
     Button(byte, boolean); // 생성자
     boolean isPushed();{
       return (digitalRead(_pin) == LOW)? true:false;
     }
     boolean isPushed(); // 버튼이 눌렸다면 true를 반환하는 멤버 함수
   private:
     byte _pin; // 연결된 핀
     boolean _internalPullup; //내부에 풀업이 되었는가
};
// 생성자의 구현
inline Button::Button(byte pin, boolean internalPullUp = true) {
   _pin = pin;
   _internalPullup = internalPullUp;
   if (_internalPullup)
       pinMode(_pin, INPUT_PULLUP);
   else
       pinMode(_pin, INPUT);
}

 단 한 가지 주의할 점은 컴파일러는 클래스 선언부에 바로 구현된 멤버 함수들에 대해서는 inline선언이 없어도 인라인 함수로 자동으로 처리한다. 따라서 이 예에서 isPushed()함수는 인라인 함수로 자동으로 간주된다.



Posted by 살레시오
,