인라인 함수와 전 처리기 매크로


답변:


127

전 처리기 매크로는 코드에 적용된 대체 패턴 일뿐입니다. 컴파일이 시작되기 전에 확장으로 대체되기 때문에 코드의 거의 모든 곳에서 사용할 수 있습니다.

인라인 함수는 본문이 호출 사이트에 직접 삽입되는 실제 함수입니다. 함수 호출이 적절한 경우에만 사용할 수 있습니다.

이제 함수와 같은 컨텍스트에서 매크로 대 인라인 함수를 사용하는 한 다음 사항에 유의하십시오.

  • 매크로는 형식에 안전하지 않으며 구문 적으로 올바른지 여부에 관계없이 확장 할 수 있습니다. 컴파일 단계에서는 매크로 확장 문제로 인한 오류를보고합니다.
  • 예상치 못한 상황에서 매크로를 사용하면 문제가 발생할 수 있습니다.
  • 매크로는 다른 매크로를 확장 할 수 있다는 점에서 더 유연합니다. 반면 인라인 함수가 반드시이 작업을 수행하는 것은 아닙니다.
  • 매크로는 확장으로 인해 부작용이 발생할 수 있습니다. 입력 표현식은 패턴에 나타날 때마다 복사되기 때문입니다.
  • 인라인 함수가 항상 인라인되는 것이 보장되는 것은 아닙니다. 일부 컴파일러는 릴리스 빌드에서만이 작업을 수행하거나 그렇게하도록 특별히 구성된 경우에만 수행합니다. 또한 경우에 따라 인라이닝이 불가능할 수 있습니다.
  • 인라인 함수는 변수 (특히 정적)에 대한 범위를 제공 할 수 있으며, 전 처리기 매크로는 코드 블록 {...}에서만이 작업을 수행 할 수 있으며 정적 변수는 정확히 동일한 방식으로 작동하지 않습니다.

39
인라인 함수가 항상 인라인되는 것이 보장되는 것은 아닙니다. 컴파일러가 인라인을 사용하면 더 느린 코드를 생성하는 등의 경우 인라인되지 않기 때문입니다. 컴파일러는 엔지니어가 할 수없는 많은 분석을 수행하고 올바른 작업을 수행합니다.
Martin York

14
재귀 함수는 대부분의 컴파일러가 인라인을 무시하는 또 다른 예라고 생각합니다.
LBushkin

이 경우 C ++와 C에서 중요한 차이점이 있습니까?
rzetterberg 2011 년

7
언급되지 않은 한 가지 점은 인라인이 컴파일 플래그의 영향을받을 수 있다는 것입니다. 예를 들어 최대 속도 (예 : GCC -O2 / -O3)로 빌드 할 때 컴파일러는 많은 함수를 인라인하도록 선택하지만 최소 크기 (-Os)로 빌드 할 때 일반적으로 한 번만 호출되는 함수 (또는 매우 작은 함수)를 인라인합니다. ). 매크로에는 그러한 선택이 없습니다.
dbrank0

매크로는 인라인 함수가 가능한 동안 액세스 지정자 (예 : 개인 또는 보호)로 덮을 수 없습니다.
Hit 's

78

첫째, 전 처리기 매크로는 컴파일 전 코드에서 "복사 붙여 넣기"입니다. 따라서 유형 검사 가 없으며 일부 부작용 이 나타날 수 있습니다.

예를 들어 두 값을 비교하려는 경우 :

#define max(a,b) ((a<b)?b:a)

max(a++,b++)예를 들어 사용하면 부작용이 나타납니다 ( a또는 b두 번 증가합니다). 대신 (예 :)

inline int max( int a, int b) { return ((a<b)?b:a); }

3
부작용 외에도 매크로가 추가 작업 부하를 도입 할 수 있다는 예를 추가하고 싶습니다 max(fibonacci(100), factorial(10000)). 더 큰 작업 은 두 번 계산됩니다. (
watashiSHUN

모두가 Type Checking에 대해 이야기하지만 실제 예제를 제공했기 때문에이 답변을 찬성했습니다.
Ivanzinho

16

Inline 함수는 컴파일러에 의해 확장되며, 매크로는 전처리기에 의해 확장되며 이는 단순한 텍스트 대체입니다.

  • 함수 호출 중에 유형 검사가 수행되는 동안 매크로 호출 중에 유형 검사가 없습니다.

  • 인수 및 작업 순서의 재평가로 인해 매크로 확장 중에 원하지 않는 결과와 비 효율성이 발생할 수 있습니다. 예를 들면

    #define MAX(a,b) ((a)>(b) ? (a) : (b))
    int i = 5, j = MAX(i++, 0);

    결과적으로

    int i = 5, j = ((i++)>(0) ? (i++) : (0));
  • 매크로 인수는 매크로 확장 전에 평가되지 않습니다.

    #define MUL(a, b) a*b
    int main()
    {
      // The macro is expended as 2 + 3 * 3 + 5, not as 5*8
      printf("%d", MUL(2+3, 3+5));
     return 0;
    }
    // Output: 16`
  • return 키워드는 함수의 경우처럼 값을 반환하기 위해 매크로에서 사용할 수 없습니다.

  • 인라인 함수는 오버로드 될 수 있습니다.

  • 매크로에 전달 된 토큰은 Token-Pasting operator라는 연산자 ##을 사용하여 연결할 수 있습니다.

  • 매크로는 일반적으로 인라인 함수를 사용하여 함수 호출 (서브 루틴으로의 점프 방지) 중에 시간 오버 헤드 (초과 시간)를 제거하는 코드 재사용에 사용됩니다.


13

주요 차이점은 유형 검사입니다. 컴파일러는 입력 값으로 전달하는 것이 함수에 전달할 수있는 유형인지 확인합니다. 이는 전 처리기 매크로의 경우 사실이 아닙니다. 유형 검사 전에 확장되어 버그를 감지하기 어렵고 심각 할 수 있습니다.

여기 에 몇 가지 덜 분명한 요점이 설명되어 있습니다.


11

이미 주어진 것들에 또 다른 차이점을 추가하려면 #define디버거에서 단계를 수행 할 수 없지만 인라인 함수를 통해 단계를 수행 할 수 있습니다.



3

인라인 함수는 매크로와 유사합니다 (함수 코드는 컴파일 타임에 호출 지점에서 확장되기 때문). 인라인 함수는 컴파일러에 의해 구문 분석되는 반면 매크로는 전처리기에 의해 확장됩니다. 결과적으로 몇 가지 중요한 차이점이 있습니다.

  • 인라인 함수는 일반 함수에 적용되는 유형 안전의 모든 프로토콜을 따릅니다.
  • 인라인 함수는 함수 선언에 인라인 키워드를 포함한다는 점을 제외하고는 다른 함수와 동일한 구문을 사용하여 지정됩니다.
  • 인라인 함수에 인수로 전달 된 표현식은 한 번 평가됩니다.
  • 경우에 따라 매크로에 인수로 전달 된 식을 두 번 이상 평가할 수 있습니다. http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx

  • 매크로는 사전 컴파일 시간에 확장되므로 디버깅에 사용할 수 없지만 인라인 함수를 사용할 수 있습니다.

- 좋은 기사 : http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;


2

인라인 함수는 값 의미를 유지하는 반면 전 처리기 매크로는 구문을 복사합니다. 인수를 여러 번 사용하면 전 처리기 매크로로 매우 미묘한 버그를 얻을 수 있습니다. 예를 들어 인수에 "i ++"와 같은 변이가 포함되어 있으면 두 번 실행되는 것은 상당히 놀라운 일입니다. 인라인 함수에는이 문제가 없습니다.


1

인라인 함수는 일반 함수처럼 구문 적으로 작동하여 함수 지역 변수에 대한 유형 안전성과 범위를 제공하고 메서드 인 경우 클래스 멤버에 대한 액세스를 제공합니다. 또한 인라인 메서드를 호출 할 때 개인 / 보호 제한을 준수해야합니다.


1

매크로 함수와 인라인 함수 의 차이점을 알기 위해서는 먼저 그것들이 정확히 무엇인지, 언제 사용해야하는지 알아야합니다.

기능 :

int Square(int x){
return(x*X);
}
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • 함수 호출에는 관련된 오버 헤드가 있습니다. 함수가 실행을 마친 후 반환해야하는 위치를 알아야하고 값을 스택 메모리에 저장해야하기 때문입니다.

  • 작은 응용 프로그램의 경우 문제가되지 않지만 매초 수천 건의 트랜잭션이 발생하는 금융 응용 프로그램의 예를 들어 보겠습니다. 우리는 함수 호출을 사용할 수 없습니다.

매크로 :

# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • 매크로는 전처리 단계에서 작동합니다. 즉,이 단계에서 # 키워드로 작성된 문은 내용으로 대체됩니다.

int 결과 = Square (x * x)

그러나 매크로에는 이와 관련된 버그가 있습니다.

#define Square(x) x*x
int main() {
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}

여기서 출력은 36아니라 11 입니다.

인라인 기능 :

inline int Square(int x) {
    return x * x;
}

int main() {
    using namespace std;
    int val = 5;
    int result = Square(val + 1);
    cout << result << endl;
    return 0;
}

출력 36

Inline 키워드는 컴파일러에게 함수 호출을 함수 본문으로 대체하도록 요청합니다. 여기서는 먼저 표현식을 평가 한 다음 전달하기 때문에 출력이 정확합니다. 반환 주소 및 스택을 저장할 필요가 없으므로 함수 호출 오버 헤드를 줄입니다. 함수 인수에는 메모리가 필요하지 않습니다.

매크로와 인라인 함수 비교 :

  1. 매크로는 대체를 통해 작동하지만 인라인 함수에서는 함수 호출이 본문으로 대체됩니다.
  2. 매크로는 대체로 인해 오류가 발생하기 쉬운 반면 인라인 함수는 사용하기에 안전합니다.
  3. 매크로에는 주소가 없지만 인라인 함수에는 주소가 있습니다.
  4. 매크로는 여러 줄의 코드와 함께 사용하기 어렵지만 인라인 함수는 그렇지 않습니다.
  5. C ++에서 매크로는 멤버 함수와 함께 사용할 수 없지만 인라인 함수는 사용할 수 있습니다.

결론:

인라인 함수는 성능을 향상시키고 사용하기에 안전하고 함수 호출 오버 헤드도 줄이므로 매크로보다 때때로 더 유용합니다. 컴파일러에 대한 요청 일 뿐이며 특정 함수는 다음과 같이 인라인되지 않습니다.

  • 큰 기능
  • 조건부 인수가 너무 많은 함수
  • 순환 코드 및 루프 등이있는 코드

그것은 좋은 일입니다. 왜냐하면 그것은 컴파일러가 다른 방식으로 일을하는 것이 최선이라고 생각할 때입니다.


비고처럼 : 매크로는 대괄호를 사용하여 동일한 숫자로 평가되도록 수정할 수 있습니다. 그러나 구현 중 절대 멍청한 대체와 모든 경우에 대해 생각해야하기 때문에 여전히 오류가 발생하기 쉽습니다.
mike

0

GCC (다른 사람에 대해서는 잘 모르겠습니다)에서 함수를 인라인으로 선언하는 것은 컴파일러에 대한 힌트 일뿐입니다. 함수가 호출 될 때마다 함수 본문을 포함할지 여부를 결정하는 것은 하루가 끝날 때 컴파일러가 결정합니다.

인라인 함수와 전 처리기 매크로의 차이는 비교적 큽니다. 전 처리기 매크로는 하루가 끝날 때 텍스트를 대체하는 것입니다. 컴파일러가 인수 및 반환 유형에 대한 유형 검사를 수행 할 수있는 많은 기능을 포기합니다. 인수의 평가는 매우 다릅니다 (함수에 전달하는 표현식에 부작용이있는 경우 디버깅 시간이 매우 즐거워집니다). 함수와 매크로를 사용할 수있는 위치에는 미묘한 차이가 있습니다. 예를 들어 다음과 같은 경우 :

#define MACRO_FUNC(X) ...

MACRO_FUNC는 분명히 함수의 본문을 정의합니다. 함수를 사용할 수있는 모든 경우에 올바르게 실행되도록 특별한주의가 필요합니다. 예를 들어 잘못 작성된 MACRO_FUNC는 오류를 일으킬 수 있습니다.

if(MACRO_FUNC(y)) {
 ...body
}

정상적인 기능을 아무 문제없이 사용할 수 있습니다.


0

코딩의 관점에서 인라인 함수는 함수와 같습니다. 따라서 인라인 함수와 매크로의 차이점은 함수와 매크로의 차이점과 동일합니다.

컴파일의 관점에서 인라인 함수는 매크로와 유사합니다. 호출되지 않고 코드에 직접 삽입됩니다.

일반적으로 인라인 함수를 약간의 최적화가 혼합 된 일반 함수로 간주해야합니다. 대부분의 최적화와 마찬가지로 실제로 적용할지 여부를 결정하는 것은 컴파일러의 몫입니다. 종종 컴파일러는 프로그래머가 함수를 인라인하려는 시도를 여러 가지 이유로 기꺼이 무시합니다.


0

인라인 함수는 반복적이거나 반복적 인 명령문이있는 경우 함수 호출로 작동하여 명령의 반복 실행을 방지합니다. 프로그램의 전체 메모리를 절약하는 데 매우 유용합니다.


-1
#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{ 
    return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases. 
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
 return a*a*a;
}
int main()
{
 cout<<NUMBER<<endl<<number()<<endl;
 cout<<CUBE(1+3); //Unexpected output 10
 cout<<endl<<cube(1+3);// As expected 64
 return 0;
}

매크로는 실제 함수 호출 오버 헤드를 포함하지 않으므로 일반적으로 함수보다 빠릅니다.

매크로의 몇 가지 단점 : 타입 검사가없고 간단한 교체를 유발하므로 디버그하기 어려움 매크로에는 네임 스페이스가 없으므로 코드의 한 섹션에있는 매크로가 다른 섹션에 영향을 미칠 수 있습니다. 매크로는 위의 CUBE () 예제와 같이 부작용을 일으킬 수 있습니다.

매크로는 일반적으로 하나의 라이너입니다. 그러나 한 줄 이상으로 구성 될 수 있으며 함수에는 이러한 제약이 없습니다.


당신은 얼마나 더 재미에서 어떻게해야합니까 #define TWO_N(n) 2 << n다음과 cout << CUBE(TWO_N(3 + 1)) << endl;? (그것은과 출력의 라인을 종료하는 것이 좋습니다 endl그것을 시작하는 것보다 있습니다.)
조나단 레플러
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.