inline int factorial(int n)
{
if(!n) return 1;
else return n*factorial(n-1);
}
내가 이것을 읽었을 때 컴파일러가 올바르게 처리하지 않으면 위의 코드가 “무한 컴파일”로 이어질 것이라는 것을 알았습니다.
컴파일러는 함수를 인라인할지 여부를 어떻게 결정합니까?
답변
첫째, inline
함수 의 스펙은 힌트 일뿐입니다. 컴파일러는 inline
한정자의 유무를 완전히 무시할 수 있으며 종종 무시합니다 . 즉, 상기와 더불어, 컴파일러 수 는 무한 루프 언 롤링 수만큼 재귀 함수를 인라인. 단순히 기능을 “롤”할 수있는 수준에 제한을 두어야합니다.
최적화 컴파일러는 다음 코드를 사용할 수 있습니다.
inline int factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
int f(int x)
{
return factorial(x);
}
이 코드로 :
int factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
int f(int x)
{
if (x <= 1)
{
return 1;
}
else
{
int x2 = x - 1;
if (x2 <= 1)
{
return x * 1;
}
else
{
int x3 = x2 - 1;
if (x3 <= 1)
{
return x * x2 * 1;
}
else
{
return x * x2 * x3 * factorial(x3 - 1);
}
}
}
}
이 경우 기본적으로 함수를 3 번 인라인했습니다. 일부 컴파일러 는 이 최적화를 수행합니다. MSVC ++는 재귀 함수 (최대 20 개)에서 수행 될 인라인 레벨을 조정하는 설정을 가지고 있습니다.
답변
실제로 컴파일러가 지능적으로 작동하지 않으면 inline
d 함수의 사본을 재귀 적으로 삽입 하여 무한히 큰 코드를 작성 하려고 할 수 있습니다 . 그러나 대부분의 최신 컴파일러는이를 인식합니다. 그들은 다음 중 하나를 수행 할 수 있습니다.
- 전혀 함수를 인라인하지 않습니다
- 특정 깊이까지 인라인하고 종료되지 않은 경우 표준 함수 호출 규칙을 사용하여 함수의 개별 인스턴스를 호출하십시오. 이렇게하면 많은 일반적인 경우를 고성능 방식으로 처리 할 수 있으며 통화 깊이가 큰 드문 경우에는 대체 할 수 있습니다. 이것은 또한 함수 코드의 인라인 버전과 별도 버전을 유지한다는 것을 의미합니다.
사례 2의 경우 많은 컴파일러 #pragma
에서이 작업을 수행 할 최대 깊이를 지정하도록 설정할 수 있습니다. gcc 에서는 명령 행에서이 정보를 전달할 수도 있습니다 --max-inline-insns-recursive
(자세한 내용은 여기 참조 ).
답변
AFAIK GCC는 가능한 경우 재귀 함수에서 테일 콜 제거를 수행합니다. 그러나 함수는 꼬리 재귀가 아닙니다.
답변
컴파일러는 호출 그래프를 만듭니다. 사이클 자체가 호출되는 것을 감지하면 함수는 더 이상 특정 깊이 (n = 1, 10, 100, 컴파일러가 조정 된대로) 후에 인라인되지 않습니다.
답변
일부 재귀 함수는 루프로 변환되어 효과적으로 무한히 인라인됩니다. 나는 gcc가 이것을 할 수 있다고 생각하지만 다른 컴파일러에 대해서는 모른다.
답변
이것이 일반적으로 작동하지 않는 이유는 이미 제공된 답변을 참조하십시오.
“각주”로서 템플릿 메타 프로그래밍을 사용하여 찾고있는 효과를 얻을 수 있습니다 (적어도 예제로 사용중인 계승에 대해서는) . Wikipedia에서 붙여 넣기 :
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
답변
컴파일러는 이러한 종류의 것들을 감지하고 방지하기 위해 호출 그래프를 만듭니다. 따라서 함수가 자체적으로 호출되고 인라인이 아니라는 것을 알 수 있습니다.
그러나 주로 인라인 키워드와 컴파일러 스위치에 의해 제어됩니다 (예를 들어 키워드 없이도 작은 함수를 자동 인라인으로 만들 수 있습니다). 코드에서 생성 한 호출