C전처리와 빌드

inline 함수

함수 호출 오버헤드를 줄이는 `static inline`이 함수형 매크로보다 안전한 이유, 컴파일러가 `inline`을 힌트로만 취급하는 이유, C99 `inline`의 외부 링키지 규칙을 정리합니다.

마지막 수정 2026년 3월 26일

기본 패턴

c
// static inline — 헤더에서 정의하는 가장 일반적인 패턴
static inline int max(int a, int b) {
    return a > b ? a : b;
}

// 함수형 매크로 대신 사용
// #define MAX(a, b) ((a) > (b) ? (a) : (b))  // ❌ 이중 평가 위험

설명

inline이 왜 필요한가 — 함수 호출 오버헤드

일반 함수를 호출할 때는 인자를 스택에 쌓고, 리턴 주소를 저장하고, 점프하는 오버헤드가 있습니다. inline 키워드는 컴파일러에게 함수 호출 대신 본문을 호출 위치에 직접 펼쳐(inlining)달라는 힌트를 줍니다. 함수가 짧고 자주 호출될 때 효과가 있습니다.

c
static inline int square(int x) {
    return x * x;
}

// 컴파일러가 inline 처리하면 아래와 동일하게 최적화
// int result = 5 * 5;  — 함수 호출 없음
int result = square(5);

함수형 매크로보다 안전한 이유

매크로는 텍스트 치환이라 인자가 여러 번 평가될 수 있습니다. static inline은 일반 함수처럼 타입 검사를 하고 인자를 한 번만 평가합니다.

c
// ❌ 매크로 — 이중 평가
#define SQUARE(x) ((x) * (x))
int i = 3;
int r = SQUARE(i++);   // (i++) * (i++) — i가 두 번 증가, 결과 예측 불가

// ✅ static inline — 한 번만 평가
static inline int square_safe(int x) {
    return x * x;
}
int i2 = 3;
int r2 = square_safe(i2++);   // i2++은 한 번만 — r2 = 9, i2 = 4

static inline vs inline

형태링키지사용 위치
static inline파일 내부(internal) — 각 번역 단위에 복사본헤더 파일에서 정의
inline (C99)외부 정의 별도 필요헤더 + .cextern inline

헤더에서 인라인 함수를 정의할 때는 항상 static inline을 씁니다. inline만 쓰면 여러 .c가 헤더를 포함할 때 링크 오류가 발생할 수 있습니다.

c
// utils.h
static inline int clamp(int val, int lo, int hi) {
    if (val < lo) return lo;
    if (val > hi) return hi;
    return val;
}

// 여러 .c 파일이 utils.h를 include해도 충돌 없음
// static이 파일 범위로 한정하기 때문

컴파일러는 inline을 힌트로만 취급

inline은 강제가 아니라 제안입니다. 함수가 너무 크거나, 재귀적이거나, 함수 포인터로 사용되면 컴파일러가 무시합니다. 반대로 inline이 없어도 컴파일러가 자체 판단으로 인라이닝할 수 있습니다.

c
// 재귀 — 인라이닝 불가 (무한 전개)
static inline int factorial(int n) {   // inline 무시됨
    return n <= 1 ? 1 : n * factorial(n - 1);
}

// 함수 포인터 — 실제 함수 주소 필요
typedef int (*fn_t)(int, int);
fn_t fp = max;   // max의 주소 필요 → 인라이닝 불가

빠른 정리

상황적합한 선택
짧은 유틸리티 함수 (헤더)static inline
타입 안전한 매크로 대체static inline
매크로가 여전히 필요한 경우문자열화, __VA_ARGS__, COUNTOF
강제 인라이닝 (GCC)__attribute__((always_inline))
인라이닝 금지 (GCC)__attribute__((noinline))

주의할 점

inline만 쓰고 static을 붙이지 않으면 여러 번역 단위에서 ODR(one definition rule) 위반이 발생할 수 있습니다.

c
// utils.h — ❌ static 없이 inline만
inline int add(int a, int b) { return a + b; }

// a.c, b.c 둘 다 utils.h 포함 시 링크 오류 가능
// (C99는 외부 정의를 별도로 요구)

// ✅ 헤더에서는 항상 static inline
static inline int add(int a, int b) { return a + b; }

inline은 컴파일러 최적화 힌트일 뿐 성능 보장이 아닙니다. 진짜 병목은 프로파일러로 찾은 후 최적화하세요.

참고 링크

1 sources