code bloating이나 그에 따른 캐시 미스 등등을 걱정해 inline 키워드를 붙일까 말까 고민하는 경우가 있는데 이제 와서 뗀석기 마냥 터보C 쓰는게 아니라면 inline 키워드 붙여놨자 컴파일러가 개무시하는 경우가 부지기수니까 고민할 필요가 없다.


보통 inline 키워드를 컴파일러에게 hint를 주는 역할을 한다고 하는데, 구석기 시대에는 그런 역할을 했을지라도 요즘에는 그런 역할보다는 linkage dire.ctive의 역할을 수행한다. 실제 인라이닝이 되는지 여부는 inline keyword 보다는 오히려 최적화 옵션에 더 많이 의존한다고 보면 됨.


inline 함수는 컴파일러가 weak symbol을 생성하도록 하는데 (실제로 인라이닝이 일어나지 않을 경우에만), 링커가 오브젝트 파일들을 링크할 때 같은 이름의 여러 weak symbol 중 하나를 선택해 링크해주므로 함수의 정의를 헤더 파일에 정의하고자 할 때는 inline 키워드를 붙여줘야 링크 에러가 나지 않는다.


실제로 weak symbol이 생성되는지를 gcc로 확인해보면 다음과 같다.


=== a.cpp (inline 키워드 없을 경우) ===

void f()

{ }


$ g++ -std=c++14 -c a.cpp

$ readelf -s a.o

...

     8: 0000000000000000     6 FUNC    GLOBAL DEFAULT    1 _Z1fv


=== a.cpp (inline 키워드를 붙일 경우) ===

[[gnu::used]] // 해당 유닛 안에서 inline 함수가 호출되지 않으면 심볼 자체가 안만들어지므로 강제로 심볼을 생성하도록 함 

inline void f()

{ }


$ g++ -std=c++14 -c a.cpp

$ readelf -s a.o

...
    10: 0000000000000000     6 FUNC    WEAK   DEFAULT    5 _Z1fv


static 함수와 비교해보자면, static 함수는 컴파일 유닛마다 internal linkage를 갖는 symbol을 생성하므로 헤더에 함수를 정의할 때 링크에러가 난다고 static 함수로 만들면 오히려 이런 경우 바이너리의 사이즈가 커짐.


역시 gcc로 확인해보면,


=== a.cpp (static 키워드를 붙일 경우) ===

static void f()

{ }


$ g++ -std=c++14 -c a.cpp

$ readelf -s a.o

...
     5: 0000000000000000     6 FUNC    LOCAL  DEFAULT    1 _ZL1fv


내가 MSVC를 전혀 안쓰고 있어서 비쥬얼 스튜디오에서는 어떻게 확인하는지 모르겠지만 비슷한 기능을 하는 프로그램이 있을겨. MSVC에서 해보고 싶은 사람은 구글링해보면 될 듯.


템플릿의 경우 기본적으로 linkage가 inline과 같아서 inline 키워드를 따로 붙여줄 필요가 없는데, 템플릿 특수화를 할 경우에는 inline 키워드를 붙여줘야 함. 이유는 역시 위에 설명한 이유 때문.



compile time constant를 인자로 받는 컴파일러 builtin 함수를 래핑한다거나 하는 진짜진짜 필수적으로 함수를 무조건 인라이닝해야하는 경우에는 [[gnu::always_inline]] 이나 __forceinline같은 compiler extension을 사용해야 함.



2줄요약


함수의 인라이닝 여부는 컴파일러가 결정하므로 '인라이닝을 할지 말지'를 고민할 필요 없음.

진짜 인라이닝을 해야할 경우 별도의 컴파일러 확장을 사용하자.