inline
C ++에서 함수 / 메소드 키워드는 언제 작성해야 합니까?
몇 가지 답변을 본 후 몇 가지 관련 질문이 있습니다.
언제해야 하지 ++ C에서 함수 / 메서드에 대한 키워드 '인라인'을 쓰기?
컴파일러는 언제 함수 / 메소드를 '인라인'으로 만들어야하는지 알 수 없습니까?
함수 / 메소드에 대해 '인라인'을 쓸 때 응용 프로그램이 멀티 스레딩 되는지 여부는 중요합니까 ?
inline
(9.3 / 2).
inline
C ++에서 함수 / 메소드 키워드는 언제 작성해야 합니까?
몇 가지 답변을 본 후 몇 가지 관련 질문이 있습니다.
언제해야 하지 ++ C에서 함수 / 메서드에 대한 키워드 '인라인'을 쓰기?
컴파일러는 언제 함수 / 메소드를 '인라인'으로 만들어야하는지 알 수 없습니까?
함수 / 메소드에 대해 '인라인'을 쓸 때 응용 프로그램이 멀티 스레딩 되는지 여부는 중요합니까 ?
inline
(9.3 / 2).
답변:
오, 내 애완 동물 친구 중 하나
inline
컴파일러에게 함수를 인라인하도록 지시하는 지시문 과 비슷 static
하거나 더 extern
지시됩니다. extern
, static
, inline
링커가 아닌 컴파일러에 의해 거의 독점적으로 사용하는 연결 지시어이다.
말했다되는 inline
컴파일러에 대한 힌트를 사용하면 함수가 인라인되어야한다 생각. 1998 년에는 그랬지만 10 년 후 컴파일러는 그러한 힌트를 필요로하지 않습니다. 코드 최적화와 관련하여 인간은 일반적으로 잘못된 것은 말할 것도 없으므로 대부분의 컴파일러는 '힌트'를 무시합니다.
static
-변수 / 함수 이름은 다른 번역 단위에서 사용할 수 없습니다. 링커는 실수로 다른 번역 단위에서 정적으로 정의 된 변수 / 함수를 사용하지 않도록해야합니다.
extern
-이 변수 / 함수 이름을이 번역 단위에서 사용하지만 정의되지 않은 경우 불평하지 마십시오. 링커는 정렬하여 extern 기호를 사용하려고 시도한 모든 코드에 주소가 있는지 확인합니다.
inline
-이 기능은 여러 번역 단위로 정의되므로 걱정하지 마십시오. 링커는 모든 변환 단위가 변수 / 함수의 단일 인스턴스를 사용하도록해야합니다.
참고 : 일반적으로 템플릿을 선언하는 inline
것은 의미가 inline
이미 있으므로 의미가 없습니다 . 그러나 명시 적 전문성 및 템플릿의 인스턴스화가 필요로inline
사용할 수 있습니다.
질문에 대한 구체적인 답변 :
C ++에서 함수 / 메소드에 대해 키워드 '인라인'을 언제 작성해야합니까?
함수를 헤더에 정의하려는 경우에만. 함수의 정의가 여러 변환 단위로 표시 될 수있는 경우에만 더 정확합니다. 헤더 파일에 작은 함수를 정의하면 코드를 최적화하면서 더 많은 정보를 처리 할 수 있으므로 헤더 파일에 작은 함수를 정의하는 것이 좋습니다. 또한 컴파일 시간이 증가합니다.
C ++에서 함수 / 메소드에 대해 키워드 '인라인'을 작성해서는 안되는 경우는 언제입니까?
컴파일러가 인라인하면 코드가 더 빨리 실행될 것이라고 생각하기 때문에 인라인을 추가하지 마십시오.
컴파일러는 언제 함수 / 메소드를 '인라인'으로 만들어야하는지 알 수 없습니까?
일반적으로 컴파일러는 사용자보다이 작업을 더 잘 수행 할 수 있습니다. 그러나 함수 정의가없는 컴파일러는 코드를 인라인하는 옵션이 없습니다. 최대한 최적화 된 코드에서는 일반적으로 private
요청 여부에 관계없이 모든 메소드가 인라인됩니다.
GCC에서 인라인을 방지하기 위해을 사용 __attribute__(( noinline ))
하고 Visual Studio에서을 사용하십시오 __declspec(noinline)
.
함수 / 메소드에 대해 '인라인'을 쓸 때 응용 프로그램이 다중 스레드인지 여부는 중요합니까?
멀티 스레딩은 어떠한 방식으로도 인라인에 영향을 미치지 않습니다.
inline
키워드가 관련이 없다는 것입니다. 그래도 올바른 아이디어가 있습니다. 일반적으로 인라인을 통해 개선 할 사항을 추측하면 오류가 발생하기 쉽습니다. 그 규칙에 대한 예외는 하나의 라이너입니다.
남은 오해를 분산시키는 확실한 예를 통해이 스레드의 모든 위대한 답변에 기여하고 싶습니다.
다음과 같은 두 가지 소스 파일이 제공됩니다.
inline111.cpp :
#include <iostream>
void bar();
inline int fun() {
return 111;
}
int main() {
std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun;
bar();
}
inline222.cpp :
#include <iostream>
inline int fun() {
return 222;
}
void bar() {
std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun;
}
사례 A :
컴파일 :
g++ -std=c++11 inline111.cpp inline222.cpp
출력 :
inline111: fun() = 111, &fun = 0x4029a0
inline222: fun() = 111, &fun = 0x4029a0
토론 :
인라인 함수에 대해 동일한 정의를 가져야하더라도 C ++ 컴파일러는 그렇지 않은 경우 플래그를 지정하지 않습니다 (실제로 별도의 컴파일 로 인해 확인할 방법이 없음). 이것을 보장하는 것은 자신의 의무입니다!
링커에 대해 불평하지 않는 한 정의 규칙 으로, fun()
로 선언됩니다 inline
. 그러나 inline111.cpp 는 fun()
컴파일러에서 처리 하는 첫 번째 변환 단위 (실제로 호출 )이므로 컴파일러 는 inline111.cppfun()
의 첫 번째 호출 발생을 인스턴스화 합니다. 컴파일러가 결정하면 되지 확장 fun()
프로그램에서 다른 곳에서의 호출에 따라 ( 예 에서 inline222.cpp )에 대한 호출 fun()
항상에서 생산의 인스턴스에 연결됩니다 inline111.cpp (호출 fun()
내부 inline222.cpp해당 번역 단위로 인스턴스를 생성 할 수도 있지만 연결되지 않은 상태로 유지됩니다). 사실, 그것은 동일한 &fun = 0x4029a0
인쇄물 에서 분명합니다 .
마지막으로,에도 불구하고 inline
컴파일러에 제안 실제로 확장 한 - 라이너를 fun()
, 그것을 무시 하기 때문에 분명하다 완전히 제안, fun() = 111
라인의 모두를.
사례 B :
컴파일 (고지 역순) :
g++ -std=c++11 inline222.cpp inline111.cpp
출력 :
inline111: fun() = 222, &fun = 0x402980
inline222: fun() = 222, &fun = 0x402980
토론 :
이 사례는 사례 A 에서 논의 된 내용을 주장한다 .
inline222.cppfun()
에서 실제 호출을 주석 처리하면 ( 예 : inline222.cpp에서 주석을 완전히 주석 처리 ) 번역 단위의 컴파일 순서에도 불구하고 첫 번째 호출 발생시 인스턴스화됩니다. inline111.cpp 이므로 케이스 B에 대한 인쇄 결과는 다음 과 같습니다 .cout
fun()
inline111: fun() = 111, &fun = 0x402980
사례 C :
컴파일 (공지 -O2) :
g++ -std=c++11 -O2 inline222.cpp inline111.cpp
또는
g++ -std=c++11 -O2 inline111.cpp inline222.cpp
출력 :
inline111: fun() = 111, &fun = 0x402900
inline222: fun() = 222, &fun = 0x402900
토론 :
-O2
최적화하는 컴파일러 장려 실제로 확장 인라인 할 수있는 기능을 (공지 사항 또한 -fno-inline
입니다 기본 최적화 옵션없이). 여기서 출력물에서 알 수 있듯이 fun()
실제로 는 특정 번역 단위 의 정의에 따라 인라인 확장 되어 두 가지 다른 출력물이 생겼습니다. 그럼에도 불구하고, 동일한 인쇄물 에서 알 수 있듯이 (표준에서 요구하는대로) 전 세계적으로 연결된 인스턴스 는 여전히 하나뿐입니다 . fun()
fun()
&fun
inline
기능을 정의되지 않은 행동으로 만드는지를 보여주는 예시적인 게시물입니다 .
.cpp
고유 한 번역 단위 인 경우를 추가해야합니다 . -flto
활성화 / 비활성화 사례를 추가하는 것이 좋습니다.
1) 요즘에는 거의 없습니다. 함수를 인라인하는 것이 좋은 생각이라면 컴파일러는 도움없이 함수를 수행합니다.
2) 항상. # 1을 참조하십시오.
(질문을 두 가지 질문으로 나눈 것을 반영하도록 편집되었습니다 ...)
inline
예를 들어 헤더 파일에서 함수 를 정의 하는 데 필요합니다 (그리고 이러한 함수를 여러 컴파일 단위로 인라인하는 데 필요함).
inline
지정자가 있으면 링커가 해당 인스턴스를 자동으로 축소하고 ODR을 사용하지 않습니다.
C ++에서 함수 / 메소드에 대해 키워드 '인라인'을 작성해서는 안되는 경우는 언제입니까?
함수가 헤더에서 선언되고 .cpp
파일에 정의 된 경우 키워드를 작성 하지 않아야 합니다.
컴파일러는 언제 함수 / 메소드를 '인라인'으로 만들지 알지 못합니까?
그러한 상황은 없습니다. 컴파일러는 함수를 인라인으로 만들 수 없습니다. 할 수있는 모든 것은 함수에 대한 일부 또는 모든 호출을 인라인하는 것입니다. 함수의 코드를 얻지 못하면 그렇게 할 수 없습니다 (이 경우 링커는 그렇게 할 수 있으면 링커가해야합니다).
함수 / 메소드에 대해 '인라인'을 쓸 때 응용 프로그램이 다중 스레드인지 여부는 중요합니까?
아니, 그건 전혀 중요하지 않습니다.
이것은 사용 된 컴파일러에 따라 다릅니다. 오늘날 컴파일러는 인간보다 인라인하는 방법을 더 잘 알고 있으며 최적화를위한 힌트보다는 연결 지시문이기 때문에 성능상의 이유로 사용해서는 안된다는 것을 맹목적으로 신뢰하지 마십시오. 나는이 이론적으로이 논쟁들이 현실과 맞닥 뜨리는 것과는 다른 주장 일 수 있다는 데 동의한다.
여러 스레드를 읽은 후 방금 작업중 인 코드에 대한 인라인의 영향에 대한 호기심을 시험해 보았습니다. 결과는 GCC의 속도를 높이고 인텔 컴파일러의 속도를 높이 지 못했습니다.
(자세한 내용 : 클래스 외부에 정의 된 중요 기능이 거의없는 수학 시뮬레이션, GCC 4.6.3 (g ++ -O3), ICC 13.1.0 (icpc -O3). 중요 포인트에 인라인을 추가하면 GCC 코드의 속도가 6 % 증가했습니다.
따라서 GCC 4.6을 최신 컴파일러로 사용할 경우 CPU 집약적 작업을 작성하고 병목 현상이 어디에 있는지 정확히 알고 있으면 인라인 지시문이 여전히 중요합니다.
실제로는 거의 없습니다. 당신이하고있는 일은 컴파일러가 주어진 함수를 인라인으로 만드는 것을 제안하는 것입니다 (예 :이 함수 / w 본문에 대한 모든 호출을 대체하십시오). 물론 보장은 없습니다 : 컴파일러는 지시어를 무시할 수 있습니다.
컴파일러는 일반적으로 이와 같은 것을 감지하고 최적화하는 데 효과적입니다.
inline
가 의미 C ++ (예를 들어, 여러 정의가 처리되는 방식에) 어떤 경우에 중요하다 (예를 들어, 템플릿)의 차이를.
gcc는 최적화를 사용하지 않고 컴파일 할 때 기본적으로 함수를 인라인하지 않습니다. 나는 Visual Studio에 대해 모른다 – deft_code
/ FAcs로 컴파일하고 어셈블리 코드를 보면 Visual Studio 9 (15.00.30729.01)에서이를 확인했습니다. 컴파일러는 디버그 모드 에서 최적화를 사용하지 않고 멤버 함수를 호출했습니다 . 함수가 __forceinline 으로 표시 되더라도 인라인 런타임 코드는 생성되지 않습니다.
라이브러리를 작성하거나 특별한 이유가 없으면 링크 타임 최적화 를 잊어 버리고 대신 inline
사용할 수 있습니다 . 컴파일 단위 전체에서 인라인하기 위해 함수 정의가 헤더에 있어야한다는 요구 사항을 제거합니다 .inline
(그러나 링크 시간 최적화를 사용하지 않는 이유가 있습니까? )
인라인 키워드는 컴파일러에게 함수 호출을 함수 본문으로 대체하도록 요청하고, 먼저 식을 평가 한 다음 전달합니다. 반환 주소를 저장할 필요가없고 함수에 스택 메모리가 필요하지 않으므로 함수 호출 오버 헤드가 줄어 듭니다. 인수.
사용시기 :
- 성능 향상
- 통화 오버 헤드를 줄입니다.
- 컴파일러에 대한 요청이므로 특정 함수에는 큰 함수가 인라인되지 않습니다.
- 조건부 인수가 너무 많은 함수
- 재귀 코드 및 루프가있는 코드
inline
C 및 C ++에서 사용하는지 여부에 관계없이 함수를 인라인 하지 않습니다. C 인라인 : stackoverflow.com/a/62287072/7194773 C ++ 인라인 : stackoverflow.com/a/62230963/7194773
C ++ 인라인에 완전히 다른 C 인라인 .
#include <iostream>
extern inline int i[];
int i [5];
struct c {
int function (){return 1;} //implicitly inline
static inline int j = 3; //explicitly inline
};
int main() {
c j;
std::cout << i;
}
inline
자체적으로 컴파일러, 어셈블러 및 링커에 영향을줍니다. 이 함수 / 데이터가 변환 단위에서 사용되는 경우에만이 함수 / 데이터에 대한 기호 만 내보내고 컴파일러가 클래스 메소드와 같은 경우에는 섹션 .section .text.c::function(),"axG",@progbits,c::function(),comdat
또는 .section .bss.i,"awG",@nobits,i,comdat
데이터 에 대해 저장하도록 어셈블러에 지시 합니다.
이것은 다음과 같습니다 .section name, "flags"MG, @type, entsize, GroupName[, linkage]
. 예를 들어 섹션 이름은 .text.c::function()
입니다. axG
섹션이 할당 가능하고 실행 가능하며 그룹에서 그룹 이름이 지정됨을 의미합니다 (M 플래그가 없으므로 entsize가 지정되지 않음). @progbits
섹션에 데이터가 있고 비어 있지 않음을 의미합니다. c::function()
그룹 이름이며 그룹은comdat
linkage는 모든 객체 파일에서 comdat로 태그가 지정된이 그룹 이름으로 발견 된 모든 섹션이 1을 제외하고 최종 실행 파일에서 제거됨을 의미합니다. 즉, 컴파일러는 번역 단위에 단 하나의 정의 만 있는지 확인한 다음 어셈블러에게 링커는 객체 파일 (1 그룹의 1 섹션)에서 자체 그룹으로 그룹화 한 다음, 객체 파일에 이름이 같은 그룹이있는 경우 최종 .exe에 하나만 포함되도록합니다. inline
사용하지 않는 것과 사용하지 않는 inline
것의 차이점 은 이제 어셈블러에서 볼 수 있으며 결과적으로 링커 는 지시문으로 인해 어셈블러 에서 일반 .data
등에 저장되지 않기 때문 .text
입니다.
static inline
클래스에서 이것은 이것이 타입 정의이며 선언이 아니라 (정적 멤버가 클래스에 정의되도록 허용) 인라인으로 만듭니다. 이제 위와 같이 동작합니다.
static inline
파일 범위에서 컴파일러에만 영향을줍니다. 이는 컴파일러에게 의미합니다.이 함수 / 데이터가 변환 단위에서 사용되는 경우에만이 함수 / 데이터에 대한 기호를 내보내고 일반 정적 기호 (.globl 지시문없이 in.text /.data에 저장)로 사용하십시오. 어셈블러에게는 이제 static
와static inline
extern inline
는 번역 단위에서이 기호를 정의하거나 컴파일러 오류를 발생시켜야한다는 의미입니다. 그가 정의 정기적으로 취급 않다면 inline
와 어셈블러와 링커가 사이에 차이가 없을 것입니다 extern inline
및 inline
이 단지 컴파일러 가드 그래서.
extern inline int i[];
extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
extern int i[5]; //declaration now has complete type
extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
extern int i[6]; //error, redeclaration with different complete type
int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type
오류 줄이없는 위의 전체가로 축소됩니다 inline int i[5]
. 분명히 당신은 않은 경우 extern inline int i[] = {5};
다음 extern
할당을 통해 명시 적 정의로 인해 무시 될 것이다.
코드를 개발하고 디버깅 할 때는 inline
제외하십시오. 디버깅이 복잡합니다.
추가 한 주요 이유는 생성 된 코드를 최적화하는 데 도움이되기 때문입니다. 일반적으로 이것은 증가 된 코드 공간을 속도로 교환하지만 때로는 inline
코드 공간과 실행 시간을 절약합니다.
알고리즘 완성 전의 성능 최적화에 대한 이런 종류의 생각은 조기 최적화 입니다.
inline
함수는 최적화로 컴파일하지 않는 한 일반적으로 인라인되지 않으므로 어떤 식 으로든 디버깅에 영향을 미치지 않습니다. 그것은 수요가 아니라 힌트라는 것을 기억하십시오.
inline
기능은 인라인되었습니다. 그들에게 의미있는 중단 점을 설정하는 것은 불가능했습니다.
inline
하면 최신 컴파일러의 코드를 개선하기 위해 아무것도 수행하지 않으므로 자체 인라인 여부를 알아낼 수 있습니다.
인라인해야 할 때 :
1. 매개 변수 전달, 제어 전달, 제어 반환 등과 같이 함수가 호출 될 때 발생하는 오버 헤드를 피하고 싶을 때
2. 기능은 작고, 자주 호출되며 인라인을 만드는 것은 80-20 규칙에 따라 프로그램 성능에 큰 영향을 미치는 인라인으로 만들려고 시도하기 때문에 실제로 유리합니다.
우리가 알고 있듯이 인라인은 레지스터와 비슷한 컴파일러에 대한 요청 일 뿐이며 객체 코드 크기로 비용이 발생합니다.
inline
최적화 힌트로서의 상태를 잃어 버렸고 대부분의 컴파일러는이를 사용하여 여러 정의에 대한 허용을 설정하는 데만 사용합니다. 더구나 C ++ 11부터는 register
'컴파일러보다 최적화하는 방법보다 컴파일러보다 잘 알고 있습니다'라는 이전 의미로 완전히 사용되지 않습니다. 현재 의미가없는 예약어 일뿐입니다.
inline
어느 정도 청취합니다 .
C ++ 인라인 함수는 클래스에서 일반적으로 사용되는 강력한 개념입니다. 함수가 인라인 인 경우 컴파일러는 컴파일시 함수가 호출되는 각 지점에 해당 함수의 코드 사본을 배치합니다.
인라인 함수를 변경하면 컴파일러가 모든 코드를 다시 한 번 바꿔야하므로 함수의 모든 클라이언트를 다시 컴파일해야 할 수 있습니다. 그렇지 않으면 이전 기능이 계속됩니다.
함수를 인라인하려면 함수 이름 앞에 키워드를 인라인으로 놓고 함수를 호출하기 전에 함수를 정의하십시오. 정의 된 함수가 한 줄 이상인 경우 컴파일러는 인라인 한정자를 무시할 수 있습니다.
클래스 정의의 함수 정의는 인라인 지정자를 사용하지 않아도 인라인 함수 정의입니다.
다음은 인라인 함수를 사용하여 최대 두 숫자를 반환하는 예입니다.
#include <iostream>
using namespace std;
inline int Max(int x, int y) { return (x > y)? x : y; }
// Main function for the program
int main() {
cout << "Max (100,1010): " << Max(100,1010) << endl;
return 0;
}