소개: Re-evaluating 기능 외침

C 프로그래밍에서, 모든 함수 호출은 오버 헤드를 소개합니다: 컴파일러는 스택에 인수를 밀어야 합니다 (또는 등록에서 전달), 함수 몸에 점프, 코드를 실행, 그리고 그 후 반환. 작은, 자주 호출된 함수를 위해, 이 오버 헤드는 실행 시간을 할 수 있습니다, 특히 성능 크리티컬 루프 또는 깊이 배열 작업. 현대 컴파일러는 적극적 최적화, 하지만 때로는 프로그래머는 극적으로 속도를 달성하기 위해 명시된 힌트를 제공해야합니다. 하나의 hints [LT]는 컴파일러가 호출하는 함수를 호출하는 함수를 호출하는 함수를 호출하는 함수를 호출합니다. [LT] [LT]는 다음과 같은 함수를 호출하는 함수를 호출합니다. [F]

Inline 기능 뒤에 기계장치

inline 함수는 키워드로 선언됩니다. 이것은 컴파일러를 인라인으로 명령하지 않습니다. 제안입니다. 컴파일러는 너무 크거나 반복적으로, 또는 최적화 수준이 낮을 때 함수를 무시할 수 있습니다. C99 및 이후 표준에서 의 semantics는 명확하게 되었습니다. 헤더 파일에 ]이 여러 가지 오류가 없는 경우, ]이 아닌 다른 명령을 포함하지 않고도, ]의 외부에 의해 정의된 함수는 다음과 같습니다. ]

  • Static 인라인: 함수는 내부 링크를 가지고 있습니다; 각 번역 단위는 자체 사본을 가져옵니다. 이것은 헤더에 정의된 작은 돕는 기능에 가장 안전한 접근입니다.
  • Extern 인라인 (C99):] 인라인 정의는 인슐린 링을 위해 몸을 제공하지만, 외부 정의는 별도로 존재해야합니다 (한 .c 파일에서). C11 이후,이 행동은 조화되었다.
  • 정적이나 배정없이 인라인: C99에서는, 이것은 외부 인라인과 유사합니다; C11에서, 외부 정의는 기능이 줄어지지 않는 경우에만 요구됩니다. 실제적으로, 는 대부분의 사용 사례에 선호됩니다.

Key insight: Inlining은 무료 점심이 아닙니다. 컴파일러는 비용 효율적인 거래 차단을 분석합니다: 모든 통화 사이트에서 기능의 몸을 삽입하는 것은 코드 크기 (코드 bloat)를 증가시킵니다. 따라서, 인라인은 작은, 자주 함수를 호출하는 것이 가장 좋습니다.

인라인 함수 Excel: 케이스 및 모범 사례 사용

작은 수학 작업

초등학생의 arithmetic을 수행하는 기능 - 제곱을 계산하고 값을 클램핑하거나 서명을 테스트하는 것과 같은 주요 후보자입니다. 함수 호출의 머리는 종종 작업 자체보다 더 큰 것입니다. 예를 들어 :

static inline int clamp(int value, int low, int high) {
 return (value < low) ? low : (value > high) ? high : value;
}

Data Structures의 Accessor 및 Mutator 기능

C의 객체 지향 패턴은 종종 데이터 캡슐화에 getters 및 setters를 사용합니다. inlining없이, 이러한 trivial 함수는 불필요한 오버 헤드를 추가합니다.

typedef struct {
 int x, y;
} Point;

static inline int point_get_x(const Point *p) {
 return p->x;
}

static inline void point_set_x(Point *p, int x) {
 p->x = x;
}

임베디드 시스템 및 실시간 코드

제한된 더미 공간과 세련한 타이밍 필요조건을 가진 환경에서, 인라인 기능은 미시간과 기억 사용법을 감소시키기 위하여 강요/pop 더미 구조를 삭제하는 필요를 삭제합니다. 그러나, 부호 크기는 기억에 똑똑히 감시되어야 합니다 마이크로 제어기.

] 을 인라인으로

  • 대기능: 여러 개의 콜 사이트에서 100개 이상의 라인 함수를 인라인으로 하는 것은 이진과 동시에 캐시 압력으로 인해 성능이 저하될 것입니다.
  • Recursive 함수: Recursion은 완전 인라인( 컴파일러가 약간의 레벨을 내리지 않을 수 있음)을 의미합니다.
  • ] 루프가있는 기능: 큰 루프가 포함 된 기능을 통합하면 상당한 혜택을 제공 할 수 없습니다.
  • Rarely 호출 함수: 오버헤드는 함수가 불행히 불린 경우, 불행히도; 단지 폐기물 공간에.

인라인 함수 Versus Macros: 상세한 비교

키워드는 표준이었다, C 프로그래머는 매크로를 사용 (]) "inlining"을 달성하지만 매크로는 텍스트 대용, 기능하지. 그들은 심각한 단점으로 온다:

  • Type safety: Macros는 type을 무시합니다. infamous ] 매크로는 와 같은 표현식을 사용할 때 위험한 부작용으로 여러 번 인수를 평가합니다.
  • Debugging: 매크로는 사전 처리 중에 사라집니다. 디버거는 그로움을 밟을 수 없습니다.
  • Compound 문: 멀티 스테이트 매크로는 ugly workarounds (예: ])를 요구합니다.
  • Name 충돌: 매크로 확장은 로컬 변수와 방해할 수 있습니다.

Inline 함수는 이러한 모든 문제를 극복: 그들은 유형 검사, 범위, 부작용 안전 인수 평가와 진정한 기능입니다. 그들은 일반 유형 시스템에 참여하고 debugged 할 수 있습니다. 매크로의 유일한 이론적 이점은 그들이 ] 유형 일반 작업 — 하지만 C11 및 C23 제안은 심지어 간격을 줄이는 것을 감소한다.

]엄지의 규칙: Prefer ] 함수 서명에 맞는 논리에 대한 매크로에 대한 기능. 간단한 일정 또는 토큰을 위한 매크로를 예약.

실제 예제: Inline Functions in Action

예 1: 광장 (알레디 제공)

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

컴파일러는 모든 통화 지시를 방출 할 가능성이 있습니다. 코드는 단순히 ]] 각 통화 사이트에서.

예 2: 문자가 Digit인지 확인

static inline int is_digit(char c) {
 return c >= '0' && c <= '9';
}

예제 3: 빠른 Min/Max (오류를 지시하는)

static inline int imax(int a, int b) {
 return (a > b) ? a : b;
}

매크로 버전과는 달리, 이것은 ]과 ]를 정확히 한번에 평가하고, 이중 증발 위험을 피합니다.

예 4 : 비트 운영 (무언 또는 바이트 스왑)

static inline uint16_t swap_bytes(uint16_t x) {
 return (x << 8) | (x >> 8);
}

이 단일 ARM의 명령을 컴파일하거나 x86에 줄어들 때 x86에 회전합니다.

Compiler Optimizations 및 인라인 키워드

키워드는 컴파일러의 인접 결정에 한 요소입니다. 대부분의 컴파일러는 공격성을 제어하는 명령 줄 플래그가 있습니다.

  • GCC/Clang: ]는 온건한 인슐린을 가능하게 합니다. 는 더 공격적인 인슐린을 가능하게 합니다. 플래그는 명시적으로 활성화될 수 있습니다. 컴파일러 허리즘에 관계없이 특정 함수를 강제로 강제로 를 이상으로 사용하십시오.
  • MSVC: ] 키워드를 사용할 수 있지만, ( 컴파일러는 여전히 특정 함수를 거부 할 수 없습니다).

GCC 속성의 예:

static inline __attribute__((always_inline)) int triple(int x) {
 return x * 3;
}

성능 크리티컬 코드의 경우, 생성된 어셈블리 (예를 들면, GCC의 ] 또는 ])를 검사하는 것이 바람직합니다. 현대 컴파일러는 높은 최적화 수준에서 를 표시하지 않고, conversely 무시할 수 있습니다 ] 함수에 대한 과도한 코드 성장이 발생할 수 있습니다.

잠재적 인 Pitfalls : 코드 Bloat 및 바이너리 크기

많은 장소에서 사용되는 기능의 모든 호출을 제거하면 텍스트 세그먼트의 크기를 크게 늘릴 수 있습니다. 이것은 특히 문제입니다.

  • Libraries: 헤더의 인라인 함수는 각 번역 단위로 확장하여, 잠재적으로 곱한 코드 크기를 곱합니다.
  • Embedded system: Flash와 RAM이 제한되어 있습니다. 1000개 장소에서 사용하는 10바이트 기능은 거의 10KB의 코드를 추가합니다.
  • 실행 캐시: 더 큰 코드가 더 많은 캐시를 놓고 전체 프로그램을 느리게 할 수 있습니다.

코드 bloat를 mitigate하려면 ]를 사용하며, 실제로 작은 기능 (일반적으로 1–5 문)에 사용됩니다. 장님으로 인리닝 전에 뜨거운 기능을 식별하려면 프로파일러를 사용하십시오. 실행 시간과 바이너리 크기를 측정하십시오.

인라인 함수는 C 표준을 넘어

키워드는 C99에서 도입되었으며 C11]C17에서 더 명확하게 설명되었습니다. C23은 추가 개선과 동일한 semantics를 유지합니다. "inline 정의"과 "external 정의" 간의 역사적인 차이는 C99에 의해 발생했습니다. C23은 모든 측면의 표준을 피합니다. ]는 C99의 표준을 피합니다.

사전 C99 컴파일러 (그게 더 드문)를 지원해야 하는 경우, 매크로 또는 외부 헤더 전용 구현으로 다시 떨어지셔야 합니다. 그렇지 않으면, 를 휴대용 및 타입 안전 대안으로 포괄합니다.

결론: 성능 엔지니어의 Toolkit에 있는 전략적인 공구

Inline 함수는 성숙한, 잘 정의된 기능의 C 언어의, 적용 가능한 judiciously, can produce measurable speed improves by eliminating function call overhead and enable cross-functionOptimizes. 그들은 거의 모든 현대 맥락에서 매크로에 우량한 입니다. 열쇠는 작게, 뜨거운 기능에 그들의 사용을 제한하고 profiling 및 집합 검사로 결과를 확인하기 위하여 입니다. 적당한 컴파일러 깃발과 결합해, 인라인 함수는 C 부호를 빨리 만들고 유지하 — 희게하 수평하게 하는 프로그램에서 작게 조화를 유지하.

더 읽기를 위해 ]GCC 문서를 인라인 함수]]cppreference entry for ]]. 실제 성능 분석, 이 ACM Queue article는 세부 사항에서 거래 오프를 탐색합니다.