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