inline 함수

  •  inline 함수란?
    • 컴파일러가 호출된 위치에 해당 함수의 코드를 직접 삽입하도록 요청하는 함수
    • 함수 호출 오버헤드를 줄이고 성능을 향상시키는 데 사용 가능
    • 컴파일러가 처리함
  • 사용하는 곳
    •  속도를 극대화해야하는 임베디드, 게임, OS등에선 사용
  • 특징
    • 함수 호출 오버헤드 감소
      • 일반적인 함수 호출은 스택에 매개변수 푸쉬, 호출 후 반환
      • inline은 이런 과정 없이 함수의 코드 그대로 삽입되므로 오버헤드 감소
    • 컴파일러가 강제하지 않음
      • 키워드를 사용한다해서 반드시 인라인 확장이 되는것이 아님
      • 컴파일러는 함수의 크기, 최적화 전략을 고려해 인라인 확장 수행 결정
    • 헤더파일에서 정의될 수 있음
      • 헤더파일에서 정의해 여러번 포함되더라도 중복 정의 오류 발생하지 않음
  • 단점
    • 바이너리 코드 증가(Code Bloat)
      • 호출되는 곳마다 코드 삽입, 함수 크기 크면 프로그램의 실행 파일크기(바이너리 크기) 증가
      • 특히 루프 내에서 자주 호출되면 코드 중복이 심해질 수 있음
    • 컴파일 및 링크 시간 증가
      • 호출될 때마다 함수 본문이 직접 삽입, 컴파일러가 처리해야될 코드양 증가
      • inline 함수가 많아지면 링커 단계에서 코드 중복을 줄이기 위한 최적화 필요
    • 디버깅이 어려움
      • 함수 호출 스택이 아니라 코드가 삽입, 디버깅시 스택 프레임에서 함수 호출이 보이지 않음
      • 호출을 추적하기 어려워 디버깅과 분석이 어려워짐
    • 재귀 함수에는 적합하지 않음
      • 재귀 함수는 호출 때마다 스택 프레임이 쌓이므로, inline 적용시 인라인이 확장되지 않음
      • 컴파일러가 무시할 가능성 높음
    • 함수 수정시 재 컴파일 필요
      • 함수 호출이 아닌 코드 자체를 삽입하기 때문에 함수 수정시 함수를 사용하는 모든파일 컴파일해야함
      • 일반 함수라면 바이너리(.obj, .lib, .dll)만 수정하면 되지만 inline 함수는 모든 사용처가 영향을 받음
  • FORCEINLINE
    • 개발 단계에서 어떤 운영체제에 inline을 사용할지 모르기 때문에 컴파일러한태 inline 함수를 알아서 강제하도록 시키는 키워드

_inline, __inline, FORCEINLINE 

  • 차이점
키워드 설명 지원 컴파일러 표준 여부
inline c++ 표준 inline 함수 모든 c++ 컴파일러 c++ 표준
_inline MSVC(visual studio)에서 제공하는 inline 함수 MSVC(visual studio) 비표준
__inline MSVC 및 일부 C 컴파일러(gcc등)에서 제공 MSVC, gcc 등 비표준
  • 등장 이유
    • 과거 컴파일러마다 inline 지원 방식이 달랐음
    • MSVC에서 _inline, __inline을 제공하여 인라인 확장을 강제하는 역할 함
    • 최신 컴파일러는 inline만으로 충분하여 거의 사용 안함
  • FORCEINLINE
    • c++에서 인라인 확장을 강제하는 메크로
    • Unreal Engine등 대규모 프로젝트에서 성능 최적화를 위해 사용
    • 강제 인라인을 적용하지만 컴파일러가 여전히 결정권을 갖기 때문에 무조건 인라인이 되는것은 아님

전방선언

  • 전방선언을 하는 이유
    • 헤더를 불러들일 때 클래스에 몸체가 없기 때문에 이 헤더를 사용할 것이라고 컴파일러에게 알려주는 것 
    • include 사용시 동일한 헤더를 참조하여 꼬이는 것을 방지
    • 헤더의 헤더가 많을수록 컴파일속도 저하, 컴파일을 모아서 할것들은 미리 컴파일된 헤더로 뺴고, 이들은 전처리기가 헤더를 컴파일하지 않고 컴파일러가 처리했을 때 앞에 명시만 해주는것(전처리기보다 컴파일러가 속도가 빨라 속도 증가)
  • #include
    • 헤더에 정의된 몸체를 물고 들어옴
    • 헤더에 포함되어있는 헤더까지 모두 물고 들어옴

 


저수준 VS 고수준

  •  저수준 언어
    • 하드웨어와 밀접하게 연관되어 있는 언어
    • CPU가 직접 이해할 수 있는 코드에 가까움
    • 메모리 관리, CUP 레지스터 조작, 포인터 조작이 가능
    • 빠른 실행속도를 보장하지만 개발이 어렵고 유지보수가 힘듦
    • 기계어(0,1로 이뤄진 이진코드), 어셈블리어, c 등
  • 고수준
    • 하드웨어보다 사람이 이해하기 쉽게 설계된 언어
    • 비지니스 로직, 알고리즘에 집중할 수 있도록 다양한 기능 제공
    • 메모리 관리가 자동화 되는 경우 많음
    • 플렛폼 독립적
    • 추상되어있는 언어
      • 여러개의 연산을 하나의 키워드로 묶고 컴파일러가 Decorder에 맞도록 쪼개주는 것
    • c++, c#, python 등

Template

  • Template란?
    • C++에서 자료형에 독립적인 코드를 작성할 수 있도록 해주는 기능
    • 자료형에 상관없이 재사용할 수 있는 코드 가능
  • 특징
    • 코드 중복 제거 : 동일한 로직을 자료형별로 여러번 구현할 필요 없음
    • 컴파일 타임 타입 결정 : 컴파일 시점에서 타입 결정
    • 일반 함수, 클래스에서도 사용 가능
  • 템플릿 특수화
    • 특정 타입에 대해서만 다른 동작을 하도록 하고싶을 때 사용 
    • 특정 자료형으로 형변화 해서 사용하는 것
  • 함수 템플릿 
  • #include<iostream> using namespace std; template<typename T> void Print(T data) { cout<<"일반 함수 : "<< data <<endl; } template<> void Print(float data) { cout<<"특수화 함수 : "<< data <<endl; } template<typename T> void Print(T* data) { cout<<"포인터 함수: "<<*data<<endl; } int main() { int i = 10; Print<int>(i);//일반 함수 float j = 20.0f; Print<float>(j);//특수화 함수 double k = 30.0; Print<double>(k);//일반 함수 int* p = &i; Print<int>(p);//포인터 함수 }
  • 클래스 템플릿
    #include<iostream>
    #include<string>
    
    using namespace std;
    
    template<typename T>
    class Character
    {
    public:
        void Set(T name)
        {
            this->name = name;
        }
    
        void Print()
        {
            cout<<"캐릭터 : "<<name<<endl;
        }
    
    private:
        T name;
    };
    
    int main()
    {
        Character<int> ob;
        ob.Set(20);
        ob.Print();
    }
  • 클래스 템플릿의 추상화
    #include<iostream>
    #include<string>
    
    using namespace std;
    
    template<typename T>
    class Character
    {
    public:
        void Set(T name)
        {
            this->name = name;
        }
    
        virtual void Print() = 0;
    
    protected:
        T name;
    };
    
    class Player : public Character<int>
    {
    public:
        void Print() override
        {
            printf("플레이어 : %d\n", name);
        }
    
    };
    
    class Enemy : public Character<string>
    {
    public:
        void Print() override
        {
            printf("에너미 : %s\n", name.c_str());
        }
    };
    
    int main()
    {
        //Character<int> ob;//순수 가상함수가 포함되어 구현하지 않으면 사용 못함
        //자식도 순수 가상함수를 구현하지 않으면 사용하지 못함
        Player p;
        p.Set(39);
        p.Print();
    
        Enemy e;
        e.Set("Test");
        e.Print();
    }

 

'자료구조 > 자료구조 정리' 카테고리의 다른 글

Stack  (0) 2025.04.23
이중 연결 리스트  (0) 2025.04.08
연결리스트  (0) 2025.03.25
선형, 비선형 자료구조  (0) 2025.03.18