extern 인라인은 무엇을합니까?


93

나는 inline그 자체로 컴파일러에 대한 제안이며, 재량에 따라 함수를 인라인 할 수도 있고 아닐 수도 있으며 링크 가능한 개체 코드도 생성 할 수 있음을 이해합니다.

나는 그것이 똑같을 것이라고 생각합니다 static inline(인라인 될 수도 있고 아닐 수도 있습니다). 그러나 인라인 될 때 ​​링크 가능한 객체 코드를 생성하지 않을 것입니다 (다른 모듈이 그것에 링크 할 수 없기 때문에).

그림에서 어디에 extern inline적합합니까?

(이것은 사용하기 때문에, 예를 들어, 내가 인라인 함수에 의해 전 처리기 매크로를 교체하려면이 기능이 인라인 도착해야 가정 __FILE____LINE__발신자에 대한 해결하지만이 호출 된 함수해야 매크로). 즉, 함수가 인라인되지 않는 경우 컴파일러 또는 링커 오류를보고 싶습니다. 않습니다 extern inline이 작업을 수행? (그렇지 않으면 매크로를 고수하는 것 외에는이 동작을 수행 할 방법이 없다고 가정합니다.)

C ++와 C간에 차이점이 있습니까?

다른 컴파일러 공급 업체와 버전간에 차이점이 있습니까?

답변:


129

K & R C 또는 C89에서 인라인은 언어의 일부가 아닙니다. 많은 컴파일러가이를 확장으로 구현했지만 작동 방식에 대한 정의 된 의미가 없습니다. GCC는 인라인 구현 가장 먼저이고, 도입 inline, static inlineextern inline구성하는 단계; 대부분의 C99 이전 컴파일러는 일반적으로 그 선두를 따릅니다.

GNU89 :

  • inline: 함수는 인라인 될 수 있습니다 (단지 힌트 일뿐입니다). 라인 외부 버전은 항상 내보내지고 외부에서 볼 수 있습니다. 따라서 이러한 인라인은 하나의 컴파일 단위에서만 정의 할 수 있으며 다른 모든 사용자는이를 라인 외부 함수로 볼 필요가 있습니다 (또는 링크 타임에 중복 기호가 표시됨).
  • extern inline 라인 외부 버전을 생성하지 않지만 하나를 호출 할 수 있습니다 (따라서 다른 컴파일 단위에서 정의해야합니다. 그러나 단일 정의 규칙이 적용됩니다. 라인 외부 버전은 컴파일러가 대신 호출하는 경우 여기에 인라인이 제공됩니다.
  • static inline파일 정적 버전을 생성 할 수는 있지만 외부에서 볼 수있는 라인 외부 버전을 생성하지 않습니다. 내 보낸 외부 심볼이나 호출이 없기 때문에 단일 정의 규칙이 적용되지 않습니다.

C99 (또는 GNU99) :

  • inline: GNU89 "extern inline"처럼; 외부에서 볼 수있는 함수는 생성되지 않지만 하나가 호출 될 수 있으므로 존재해야합니다.
  • extern inline: GNU89 "inline"처럼 : 외부에서 볼 수있는 코드가 방출되므로 최대 하나의 번역 유닛이 이것을 사용할 수 있습니다.
  • static inline: GNU89 "정적 인라인"과 같습니다. 이것은 gnu89와 c99 사이의 유일한 휴대용 제품입니다.

C ++ :

어디에서나 인라인 된 함수는 동일한 정의로 모든 곳에서 인라인되어야합니다. 컴파일러 / 링커는 심볼의 여러 인스턴스를 정렬합니다. static inline또는에 대한 정의는 extern inline없지만 많은 컴파일러가이를 가지고 있지만 (일반적으로 gnu89 모델을 따릅니다).


2
클래식 클래식 C에서 '인라인'은 키워드가 아닙니다. 변수 이름으로 사용할 수있었습니다. 이는 C89 및 사전 표준 (K & R) C에 적용됩니다.
Jonathan Leffler

당신이 맞습니다. 결정된. (K & R은 아니지만) C89에서 키워드로 예약되었다고 생각했지만 잘못 기억 한 것 같습니다
puetzk

Microsoft의 Visual C ++에 대해 추가하고 싶습니다. 함수가 인라인되도록 강제하는 __forceinline 키워드가 있습니다. 이것은 분명히 VC ++만을위한 컴파일러 특정 확장입니다.
untitled8468927

C99 "extern inline"과 지정자가 전혀 다른 점이 있습니까?
조 그래서

의미 상 아니오; 인라인이 아닌 함수와 마찬가지로 extern inline하나의 정의 규칙이 적용되며 이것이 정의입니다. 그러나 구현 정의 최적화 휴리스틱이 권장 사항에 따라 inline키워드를 "가능한 한 빨리 함수 호출"이라는 제안으로 사용하는 경우 (ISO 9899 : 1999 §6.7.4 (5), extern inlinecounts
puetzk

31

이 진술을 기반으로 __FILE__ 및 __LINE__을 오해하고 있다고 생각합니다.

호출자에 대해 해결해야하지만 호출 된 함수가 아닌 __FILE__ 및 __LINE__ 매크로를 사용하기 때문입니다.

컴파일에는 여러 단계가 있으며 전처리가 첫 번째 단계입니다. __FILE__ 및 __LINE__은 해당 단계에서 대체됩니다. 따라서 컴파일러는 이미 대체 된 인라인 함수를 고려할 수 있습니다.


14

다음과 같이 작성하려는 것 같습니다.

inline void printLocation()
{
  cout <<"You're at " __FILE__ ", line number" __LINE__;
}

{
...
  printLocation();
...
  printLocation();
...
  printLocation();

매번 다른 값이 인쇄되기를 바랍니다. Don이 말했듯이 __FILE__ 및 __LINE__은 전처리기에 의해 구현되지만 인라인은 컴파일러에 의해 구현되기 때문에 그렇지 않습니다. 따라서 어디서 printLocation을 호출하든 동일한 결과를 얻을 수 있습니다.

이 작업을 수행 할 수 있는 유일한 방법은 printLocation을 매크로로 만드는 것입니다. (예, 알아요 ...)

#define PRINT_LOCATION  {cout <<"You're at " __FILE__ ", line number" __LINE__}

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...

18
일반적인 트릭은 매크로 PRINT_LOCATION이 printLocation 함수를 호출하여 FILELINE 을 매개 변수로 전달하는 것 입니다. 이것은 함수 본문이 사소하지 않을 때 더 나은 디버거 / 편집기 / 등 동작을 초래할 수 있습니다.
Steve Jessop

@Roddy 내 솔루션을 살펴보십시오-귀하의 확장이지만 더 포괄적이고 확장 가능합니다.
열광적 인

@SteveJessop 아래 솔루션에 나열된 것과 같은 것이 있습니까?
열광적 인

3

인라인, 정적 인라인 및 외부 인라인의 상황은 복잡합니다. 특히 gcc와 C99가 동작에 대해 약간 다른 의미를 정의하기 때문입니다 (그리고 아마도 C ++도 마찬가지 일 것입니다). 여기서 C 에서 수행하는 작업에 대한 유용하고 자세한 정보를 찾을 수 있습니다 .


2

여기서 매크로는 인라인 함수가 아닌 선택입니다. 매크로가 인라인 함수를 지배하는 드문 경우입니다. 다음을 시도해보십시오.이 "MACRO MAGIC"코드를 작성했는데 제대로 작동합니다! gcc / g ++ Ubuntu 10.04에서 테스트 됨

//(c) 2012 enthusiasticgeek (LOGGING example for StackOverflow)

#ifdef __cplusplus

#include <cstdio>
#include <cstring>

#else

#include <stdio.h>
#include <string.h>

#endif

//=========== MACRO MAGIC BEGINS ============

//Trim full file path
#define __SFILE__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__ )

#define STRINGIFY_N(x) #x
#define TOSTRING_N(x) STRINGIFY_N(x)
#define _LINE (TOSTRING_N(__LINE__))

#define LOG(x, s...) printf("(%s:%s:%s)"  x "\n" , __SFILE__, __func__, _LINE, ## s);

//=========== MACRO MAGIC ENDS ============

int main (int argc, char** argv) {

  LOG("Greetings StackOverflow! - from enthusiasticgeek\n");

  return 0;
}

여러 파일의 경우 각 c / cc / cxx / cpp 파일에 동일한 내용을 포함하여 별도의 헤더 파일에 이러한 매크로를 정의합니다. 가능한 경우 매크로보다 인라인 함수 또는 const 식별자 (필요한 경우)를 선호하십시오.


2

"무엇을하나요?"라고 대답하는 대신 "내가 원하는 것을 어떻게 할 수 있습니까?"라고 대답합니다. 5 가지 종류의 인라인이 있으며 모두 GNU C89, 표준 C99 및 C ++에서 사용할 수 있습니다.

주소를 사용하지 않는 한 항상 인라인

__attribute__((always_inline))선언에 추가 한 다음 아래 사례 중 하나를 사용하여 주소를 가져올 가능성을 처리하십시오.

의미론이 필요하지 않은 경우 (예 : 특정 방식으로 어셈블리에 영향을 미치거나를 사용하기 위해 alloca) 이것을 사용해서는 안됩니다 . 컴파일러는 일반적으로 그만한 가치가 있는지 당신보다 더 잘 알고 있습니다.

인라인하고 약한 기호를 내 보냅니다 (예 : C ++, 일명 "그냥 작동하게").

__attribute__((weak))
void foo(void);
inline void foo(void) { ... }

이렇게하면 동일한 코드의 복사본이 여러 개 남고 링커는 임의로 하나를 선택합니다.

인라인, 그러나 어떤 기호도 방출하지 않음 (외부 참조 남김)

__attribute__((gnu_inline))
extern inline void foo(void) { ... }

항상 방출 (하나의 TU에 대해 이전 문제 해결)

힌트 된 버전은 C ++에서 약한 기호를 내 보냅니다. 그러나 C의 어느 방언에서나 강한 기호를 내 보냅니다.

void foo(void);
inline void foo(void) { ... }

또는 두 언어 모두에서 강력한 기호를 표시하는 힌트없이 수행 할 수 있습니다.

void foo(void) { ... }

일반적으로 정의를 제공 할 때 TU가 어떤 언어인지 알고 있으며 인라인이 많이 필요하지 않을 수 있습니다.

모든 TU에서 인라인 및 방출

static inline void foo(void) { ... }

static하나를 제외한 모든 항목에 대해 void foo(void)위에 선언을 추가 할 수 있습니다 . 이것은 깨끗한 헤더를 작성한 다음 #include인라인 정의가있는 별도의 파일 을 작성하는 "모범 사례"에 도움이됩니다 . 그런 다음 C 스타일 인라인을 사용하는 경우 #define하나의 전용 TU에서 다른 매크로를 사용하여 라인 외부 정의를 제공합니다.

extern "C"헤더가 C와 C ++ 모두에서 사용될 수 있는지 잊지 마세요 !


누락 : MSVC는 어떻습니까? 일부 C89 방언 확장 기능이 있지만 MSVC를 사용하지 않으며 nm해당 기능 을 실행하는 방법을 모릅니다 .
o11c
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.