2011-01-22 2 views
1

나는 이것을 성공하기 위해 이틀 동안 답을 찾았다. 나는이 문제를 처음부터 경험해 본 적이 없으므로 최선을 다할 것입니다. 나와 함께 견뎌주세요.최적화가 없으면 C++ 코드가 이상하게 건너 뜁니다. 어떤 아이디어?

나는 1 년 전에 만들었던 C++ 프로젝트로 돌아 갔는데, 당시 문제없이 실행되었습니다. 내가 같은 프로그램을 실행하려고 할 때 나는이 흥미롭고 엄청나게 짜증나는 문제를 보았습니다.

file.h

... 
short id; 
... 

file.cc

id = 0; 
while (id < some_large_number) 
{ 
    id = foo(); 
    if (id == 2) 
    { 
     //do something 
    } 
    else if (id == 2900) 
    { 
     //do something 
    } 
    else if (id == 30000) 
    { 
     //do something 
    } 
    else if (id == 40000) 
    { 
     //do something 
    } 
    else if (id == 45000) 
    { 
     //do something 
    } 
    else 
    { 
     //do something else 
    } 
} 

상수 숫자는 내가이 예를 들어 확장 진수 표기법으로 매크로했다 : 코드는 무엇인가 같았다. 이것은 진정한 버그 였지만 디버거는 쉽게 발견하지 못했습니다. 무슨 일이 있었는지 :

GDB를 사용하여 코드를 단계별로 실행하려고 했으므로 GDB는 매번 if (id == 30000)에 도달 한 후 곧바로 else 문으로 이동합니다. 숫자는 16 진수 표기법으로 된 매크로이므로 처음에는 40000signed short의 한계를 넘지 않았 음을 알지 못했습니다. 이것은 매우 오도하고 오랜 시간을 보냈다. 외부 라이브러리를 다시 컴파일하고 g ++를 다시 설치했다.

분명히 idunsigned short으로 수정하면 문제가 해결됩니다. 다른 문제는 컴파일러 문제처럼 보입니다. 하지만 여전히 이해할 수 없는데, 실행 중에 코드의 섹션이 완전히 건너 뛰었고 최적화가 이루어지지 않은 이유는 무엇입니까? 왜 각각의 if 문을 통과하지 않을 것이고, 그런 식으로 실제 문제를 확인할 수 있습니까? 어떤 아이디어?

고마워요. 나는 이것이 첫 번째 질문에 괜찮 으면 좋겠다.

+1

C++에서 매크로를 사용하면 요청한 것을 얻을 수 있습니다. – Puppy

+1

컴파일러에서 경고하지 않았습니까? 추가 경고 없이도 g ++ 4.5에서는 사례 레이블이 해당 유형의 최대 값을 초과한다고 불평 할 것입니다. 다른 컴파일러의 경우에는 몇 가지 플래그와 함께 추가 경고를 추가 할 수 있습니다. * 모든 경고를 읽고, 고치고 배우십시오 *. –

+0

컴파일러가 경고하지 않았습니다. 그리고 나는 -Wall 옵션을 설정했습니다. 그러나 if 문을 전환하여 사례를 전환하면 경고가 표시됩니다. 내가 사용하는 컴파일러 버전은 g ++ 4.4.3입니다. – lospro7

답변

1

short는 16 비트 길이이고 그 범위는 -32768에서 32767입니다. 따라서 결코 40000 또는 45000이 될 수 없으며 컴파일러는 (결코 도달하지 않을 것이므로) 데드 코드를 제거합니다.

+0

나는 그 첫 번째 부분을 알아 냈다. 하지만 기본적으로 컴파일러는 코드 섹션이 실행되고 절대로 실행되지 않을지를 결정합니다. 컴파일러의 일부 버전은이를보고하는 것처럼 보이지만 다른 버전에서는 그렇지 않습니다. 나는 그것이 다시 일어난다면 명심하겠습니다. – lospro7

3

gcc에서 모든 경고를 활성화하면 컴파일 할 때 발생한다는 경고 메시지가 표시됩니다.

+0

+1 컴파일러 수준에 따라 추가 경고 없이도 경고 할 수 있습니다 (g ++ 4.5에서는 플래그가 없으며 4.0/4.2는 그렇지 않습니다). –

+0

불행히도 이것은 그렇지 않았습니다 (g ++ 4.4.3). if 문을 스위치 케이스로 변환하면 경고 만받습니다. – lospro7

1

내 결론은 당신과 같습니다 : "최적화"가 켜져 있지 않아도 최적화 된 것처럼 보입니다. 아마도 이러한 상수 술어 "always true"/ "always false"는 코드 생성 단계에서 직접적으로 코드를 건너 뛰는 데 사용됩니다. 즉, -O 스위치 최적화가 수행되는 것보다 빠릅니다. 그냥 추측.

1

GCC는 뛰어난 최적화 컴파일러이지만 -Werror, -Wall 등을 통해 오류 및 경고 정보를 사용할 수있는 경우에도 GCC는 진단 컴파일이 수행하는 것과 동일한 수준의 정보를 생성하지 않습니다. 코드를 개발하는 동안 버그와 오류를 찾는데 도움이되는 진단 컴파일러 인 Clang을 사용하는 것이 좋습니다. Clang은 GCC와의 호환을 목적으로하고 있으며, 좀 더 밀교적인 기능을 제외하고는 Makefile의 두 항목 사이에서 내 CC를 변경하는 데 아무런 문제가 없습니다.

최적화 컴파일러이기 때문에 GCC는 기본적으로 불필요한 코드 제거를 사용한다고 생각합니다. 이로 인해 컴파일러에서 발견 한 모든 분기 (예 : id 변수의 범위를 벗어난 분기)는 제거 될 수 있습니다. 이러한 유형의 불필요한 코드 제거를 비활성화 할 수 있습니다.

1

컴파일하는 동안 C++ 컴파일러는 코드를 살펴보고 코드의 어떤 부분이 어떤 순서로 실행되는지 확인합니다. 컴파일러가 코드의 일부가 절대로 실행되지 않을 것이라고 판단하면 최적화되지 않습니다.예를 들어

는 :

여기
int i = 0; 
if(i == 1) { 
    printf("This will never be printed\n"); 
} 

, 그것은 실행되지 않을 것 같이 경우 문을 최적화 할 이유가 없다.

-Wall 수단이 모든 경고를 표시

g++ -Wall mycode.c

mycode.c 프로젝트 파일입니다 : 당신이 컴파일하는 경우

는 인스턴스의이 종류는 포착 될 것이다.

GDB를 통한 실행은 프로그램의 현재 흐름을 보여줍니다. 분기 (if 문에서)가 거짓이면 코드의 해당 섹션을 통과하는 이유는 무엇입니까? if-elseif-else 문에서 하나의 분기만을 사용할 수 있습니다.

나는 당신을 돕기를 바랍니다.

관련 문제