본문 바로가기
카테고리 없음

[언리얼] C++ FORCEINLINE 매크로, 인라인 함수와 차이점은? 장점과 단점 분석

by 연지니어스 2025. 3. 19.

언리얼 엔진에서 FORCEINLINE 키워드란?

1. FORCEINLINE 키워드 개요

언리얼 엔진에서는 성능 최적화를 위해 다양한 C++ 키워드를 활용할 수 있으며, 그중 하나가 FORCEINLINE이다. 이 키워드는 함수 인라이닝을 강제하는 역할을 한다. 일반적으로 C++에서는 inline 키워드를 사용하여 함수의 인라인화를 유도할 수 있지만, 컴파일러가 특정 조건에 따라 이를 무시할 수도 있다. 하지만 FORCEINLINE을 사용하면 컴파일러가 강제로 해당 함수를 인라인 처리하도록 한다.

2. FORCEINLINE 키워드 사용법

언리얼 엔진에서는 FORCEINLINE 키워드를 사용하여 특정 함수가 반드시 인라인되도록 강제할 수 있다. FORCEINLINE은 언리얼 엔진이 제공하는 FORCEINLINE 매크로를 사용하여 정의할 수 있다.

FORCEINLINE int Add(int A, int B) {
    return A + B;
}

위 코드에서 FORCEINLINE 매크로는 플랫폼별로 적절한 강제 인라인 지시어를 포함하고 있어, 함수가 반드시 인라인되도록 만든다.

 

forceinline키워드 이미지
forceinline키워드 이미지

 

이처럼 보통 간단한 함수 정의, 단순한 리턴값만을 포함할 때 FORCEINLINE 매크로를 사용하여 헤더 파일에서 선언과 동시에 정의한다.

 


INLINE키워드와 FORCEINLINE의 차이점

1. 컴파일러의 처리 방식

  • inline: 함수의 인라인화를 제안하는 키워드로, 컴파일러가 최적화 판단에 따라 인라인 여부를 결정할 수 있다.
  • FORCEINLINE: 언리얼 엔진에서 제공하는 강제 인라인 매크로로, 반드시 인라인되도록 지시한다. 컴파일러가 인라인을 무시할 수 없도록 강제한다.

2. 사용 목적

  • inline: 일반적으로 자주 호출되는 작은 함수에서 사용하면 성능 최적화에 도움이 될 수 있다.
  • FORCEINLINE: 특정 성능 최적화가 필요한 경우(예: 빈번한 연산 함수) 반드시 인라인되도록 강제할 때 사용한다.

3. 결과적인 최적화 효과

  • inline: 상황에 따라 최적화되지 않을 수도 있다.
  • FORCEINLINE: 강제적으로 인라인되므로, 오버헤드 감소 효과가 확실하다. 하지만 코드 크기가 증가할 위험이 있다.

키워드 없이 헤더 파일에서 함수 선언과 정의를 작성한다면?

 

헤더 파일에서 함수 선언과 정의를 함께 작성하면, 기본적으로 컴파일러는 인라인화 후보로 간주한다. 하지만 이것이 반드시 인라인된다는 보장은 없다.

 

  • 헤더 파일에서 함수 정의를 직접 제공하면, 이 함수는 **ODR(One Definition Rule)**을 위반하지 않기 위해 컴파일될 때마다 여러 번 복사될 위험이 있다.
  • 하지만 컴파일러는 중복 정의를 방지하고자 이를 암묵적으로 inline 함수로 간주한다.
  • 따라서 inline을 명시하지 않아도 대부분의 경우 인라인 최적화가 적용될 수 있다.

 

.h //헤더파일
int Add(int A, int B) { return A + B;}

inline int Add(int A, int B) { return A + B;}

FORCINLINE int Add(int A, int B) { return A + B;}

 

1번은 인라인화 보장 X, 중복 정의 안전성 X

 

  • 이 함수가 여러 .cpp 파일에서 #include되면, 각각의 번역 단위에서 중복 정의될 수 있다.
  • 이는 **링커 오류(Linker Error)**를 유발할 가능성이 있다.

 

 

2번은 인라인화 보장 X, 중복 정의 안전성 O

 

  • inline 키워드를 추가하면, ODR을 자동으로 회피할 수 있도록 컴파일러가 처리한다.
  • 여러 번 정의되더라도, 링커가 중복 정의를 허용하고 최적화하여 하나만 유지할 수 있도록 한다.

 

 

3번은 인라인화 보장 O, 중복 정의 안전성 O 

 

  • FORCEINLINE은 인라인을 강제하면서도 ODR을 회피하는 매크로이기 때문에, inline과 비슷한 효과를 갖는다.
  • 다른 번역 단위에서 동일한 함수를 여러 번 정의하더라도, 링커가 충돌하지 않도록 처리한다.

 

 

함수 정의 방식 중복 정의 안전성 인라인 가능성 강제 인라인 여부
헤더에서 함수 정의만 제공 컴파일러가 최적화 여부 판단
inline 명시 컴파일러가 최적화 여부 판단
FORCEINLINE 명시 무조건 인라인됨

3. FORCEINLINE 키워드의 장점

3.1 성능 최적화

인라인 함수는 호출 오버헤드를 제거하여 실행 속도를 향상시킨다. 특히, 짧고 빈번하게 호출되는 함수에 적용하면 CPU 레지스터를 활용하여 더 빠르게 연산할 수 있다.

3.2 캐시 최적화

함수를 인라인하면 코드가 한 곳에서 실행되므로, CPU의 명령어 캐시 효율성이 증가한다. 이로 인해 캐시 미스(Cache Miss)가 줄어들어 성능이 개선될 수 있다.

3.3 매크로보다 더 나은 가독성

전처리기 매크로(#define을 이용한 매크로)는 디버깅이 어려운 반면, FORCEINLINE은 함수 형태를 유지하면서도 인라인 최적화를 적용할 수 있다. 따라서 코드 유지보수가 더 용이하다.

 

4. FORCEINLINE 키워드의 단점

4.1 코드 크기 증가

모든 함수 호출이 인라인으로 대체되면 바이너리 크기가 증가할 수 있다. 이는 특히 코드 크기가 중요한 임베디드 시스템이나 메모리 제약이 있는 환경에서는 문제가 될 수 있다.

4.2 컴파일 시간 증가

인라인 함수가 많아지면 컴파일러가 더 많은 코드를 분석해야 하므로 빌드 시간이 길어질 수 있다. 특히 대규모 프로젝트에서는 이를 신중히 고려해야 한다.

4.3 디버깅 어려움

인라인 함수는 실제로 함수 호출이 제거되고 코드가 직접 삽입되기 때문에, 디버깅 시 함수 호출 스택을 확인하기 어려울 수 있다. 이는 함수 호출 순서를 파악하는 데 불편함을 줄 수 있다.

 

5. FORCEINLINE 디버깅 방법

FORCEINLINE으로 헤더에 정의한 함수는 디버깅이 어렵다는 단점이 있다. 이런 경우에 FORCEINLINE을 사용한 코드에서 디버깅을 쉽게 하기 위해 몇 가지 방법을 활용할 수 있다.

5.1 __declspec(noinline) 사용

일부 함수가 예상대로 인라인되지 않는지 확인하려면 강제로 인라인을 막는 __declspec(noinline) 지시어를 사용할 수 있다.

__declspec(noinline) void TestFunction() {
    // 디버깅을 위한 함수
}

이렇게 하면 강제 인라인이 적용되지 않으므로, 함수 호출 스택에서 해당 함수를 명확히 확인할 수 있다.

5.2 __forceinline을 제거하고 테스트하기

FORCEINLINE이 예상한 대로 작동하는지 확인하려면, FORCEINLINE을 제거한 후의 실행 결과를 비교해 보는 것도 방법이다. 이를 통해 성능 차이와 디버깅 가능성을 고려할 수 있다.

 

6. 결론 및 요약

아래 표는 FORCEINLINE 키워드의 주요 특징을 정리한 것이다.

항목  설명
주요 기능 함수 호출을 강제로 인라인화
장점 성능 최적화, 호출 오버헤드 제거, 캐시 최적화
단점 코드 크기 증가, 컴파일 시간 증가, 디버깅 어려움
디버깅 방법 __declspec(noinline) 사용, FORCEINLINE 제거 후 테스트

 

FORCEINLINE 키워드는 적절히 사용하면 성능 최적화에 큰 도움을 줄 수 있지만, 코드 크기 증가와 디버깅 어려움을 초래할 수 있으므로 신중한 사용이 필요하다. 특히, 언리얼 엔진과 같은 대규모 프로젝트에서는 중요한 코드 경로에서만 제한적으로 적용하는 것이 바람직하다.