2009-03-01 2 views
3

나는이 같은 코드를 가지고 있고, 나는 그것이 조금 어려운 읽고 찾을 :C/C++ 컴파일러는이 if 문을 최적화할까요?

// code2 
const bool expr1 = expensiveOperation1() && otherOperation() && foo(); 
const bool expr2 = expensiveOperation2() && bar() && baz(); 
if(expr1 || expr2){ 
    // one of the conditions met 
} 

을하지만 지금은해야 :

// code1 
if((expensiveOperation1() && otherOperation() && foo()) 
    || (expensiveOperation2() && bar() && baz()) { 
    // do something 
} 

난 그냥 다음에 변경이 더 쉽게 읽을 수 있도록하기 효율성에 관심이 있으십니까?

내 말은 code1에서 첫 번째 결합 조항이 충족되면 두 번째 문장을 살펴보기가 번거롭지 않습니다. 진술이 사실임이 이미 분명하기 때문입니다.

그러나 더 쉽게 읽을 수있는 예제에서는 cond1cond2을 모두 계산해야합니다. 또는 컴파일러는 code2code1으로 변경할 수있을 정도로 똑똑 할 것입니다. 다른 곳에서는 expr2를 사용하지 않으면됩니까?

+0

gcc/g ++ (g ++ v3.4, 정확하게 사용하고 있습니다.). – Frank

답변

24

부울 효과가있는 함수가 논리적으로는 같지 않기 때문에 필자는 그렇지 않아야한다고 말합니다.

다음은 그러나 동등한 것, 그것은 코드를 더 자기 문서화하고, 당신은 테스트 기능을 설명하는 이름을 부여 할 수있는 장점이있을 것이다 :

// code3 
inline bool combinedOp1() 
{ 
    return expensiveOperation1() && otherOperation() && foo(); 
} 

inline bool combinedOp2() 
{ 
    return expensiveOperation2() && bar() && baz(); 
} 

그리고 다음과 같이 호출을 :

if (combinedOp1() || combinedOp2()) 
{ 
    // do something 
} 
+0

게으른 평가로 인해 부작용이없는 것이 좋습니다. – tvanfosson

+0

+1 나에게서. 나는 그것을 생각해야 했어! ;-) – Frank

+0

동의했다면, 이것을 최적화하면 놀랄 것입니다. 물론 거기에는 부작용이 없어야하지만 컴파일러는이를 알 수 없습니다. 최악의 상황을 가정해야합니다. expensiveOperation의 정의가 표시되면 optmize 할 수도 있지만 안전한 내기가 아닙니다. 나는이 솔루션을 좋아한다. – jalf

19

아마도 두 번째 수표가 첫 번째 수표에 포함되지 않는 이유는 무엇입니까? 가장 비싼 검사가 완전히 비싼 작업을 건너 게으른 평가를 활용, 각 목록에서 먼저 발생하므로

// code3 
bool expr = expensiveOperation1() && otherOperation() && foo(); 
expr = expr || (expensiveOperation2() && bar() && baz()); 
if(expr){ 
    // one of the conditions met 
} 

더 나은 아직, 주변에 물건을 켭니다.

+0

니스 - 백만 년 동안 나에게 마음에 들지 않았을 단순한 것들 중 하나. –

+0

좋은 점은, expr이 const로 선언되어 두 번째 줄이 컴파일되지 않는다는 것입니다 :-) 당신이 "const bool expr1 = ...; const bool expr2 = expr1 || (...)"을 의미한다고 생각하고 있습니다. – SCFrench

+0

Cut/붙여 넣기 오류. 나는 그것을 const로 만들고 그것을 재사용하지 않을 것이다. – tvanfosson

4

글쎄, 일반적으로 컴파일러가 & & 년대와 || '의 순서를 변경하지 않습니다의 조건은 부작용을 가지고 오프 기회에. 몇 안되는 영리한 컴파일러가 정적으로 정적을 검증 할 수는 있지만 이것은 드물 것이다.

가능한 경우 값싼 작업의 순서를 변경하여 비싼 작업을 단락시킬 수 있습니다.

1

이 질문에 대한 답변은 물론 컴파일러에 따라 다릅니다. 가장 확실한 방법은이 함수에 대해 컴파일러에서 생성 된 어셈블리를 확인하는 것입니다. 대부분의 (모든?) 컴파일러는 이것을 수행하는 방법을 가지고 있습니다. 예를 들어 gcc-S 옵션을 가지고 있습니다. 어떤 기괴한 이유 때문에 대부분의 디버거가 함수에 대한 디스 어셈블리를 표시하지 못하거나이를 위해 다른 도구가있을 수 있습니다.

0

좋은 답변입니다.

필자는 컴파일러가 내 코드를 재정렬하는 데 너무 공격적이어서 좋지 않다고 덧붙이겠다.

나는 단지 컴파일러가 말한 것을 수행하기를 원한다.

나를 능가 할 수 있다면 스스로도 능가 할 수 있습니다.

2

여기에서 가장 먼저 대답해야 할 질문은 "should not"와 "maybe"입니다.그것은 결정적인 대답이 아닙니다!

컴파일러가이 작은 비트의 코드를 최적화하고 있는지 확인하려면 "어셈블리 표시 출력"플래그로 코드를 컴파일하십시오. GCC에서 그 플래그는 "-S"입니다. 그런 다음 출력 어셈블리를 살펴보고 컴파일 된 내용을 정확히 100 % 보여줍니다.

그런 다음 코드 조각으로 스 니펫 된 첫 번째 코드를 "therefromhere"에서 비교하고 컴파일러가 최적 (예 : 최소주기)을 최적화 할 때까지 수많은 코드 변경 사항을 빠르게 시도 할 수 있습니다.

asm 출력을보기에는 복잡하고 무서운 것처럼 들리지만 실제로는 약 5 분 정도 소요됩니다. 여기에 예제를 작성했습니다 : What is the fastest way to swap values in C?

+0

-1 다음 컴파일러 업데이트로 인해 깨지지 않는 코드를 생성하는 좋은 방법입니다. 언어가 보장하는 것을 항상 이해하려고 노력하십시오. 컴파일러 구현 세부 사항을 분석하기 시작하면 그 보증 중 하나를 위반하는 것으로 보이는 경우에만 시도하십시오. –

+1

필자는 언제 "오, 컴파일러의 출력 asm을보고있는 동안 ... C 코드를 이식성이 없도록 만들 었는지"를 제안했습니다. 필자는 필자의 글을 "이식성이 떨어지게 만들기"에 오해하기 위해 열심히 노력해야한다. 어리석은 사람 만 의도적으로 C 코드를 이식 할 수 없게 만듭니다. 큰 바보가 생각하지도 않으면 서 의도적으로 C 코드를 이식 할 수 없게 만듭니다. –

0

cond2 (expensiveOperation2(), bar() 및 baz()의 함수가 순수하다는 것을 알고 있으면 컴파일러에서 최적화 할 수 있습니다 (즉, 부작용이 없음). 그것들이 순수하다면 컴파일러가 그것을 인라인 함수로 만드는 것이 가장 간단한 방법이다.

가능합니다. 컴파일러는 알 수 없지만 비용이 많이 드는 작업 2() 이후로는 거의 작동하지 않을 가능성이 매우 낮습니다.

FWIW, 이러한 함수가 순수한 경우 bar() 및 baz()가 expensiveOperation2()보다 먼저 실행되도록 정렬해야합니다 (cond1의 순서와 동일).

관련 문제