2017-02-02 6 views
0

GCC는 -Wsuggest-attribute=pure-Wsuggest-attribute=const 플래그를 사용하여 순수 속성 및 속성 const에 대한 함수를 제안 할 수 있습니다. GCC가 순수하지 않거나 const 인 함수를 GCC로 선언했을 때의 영향

GCC documentation

는 말한다 :

많은 기능이 더 리턴 값을 제외하고 효과와 그 반환 값은 매개 변수 및/또는 전역 변수에 따라이 없습니다. 이러한 함수는 산술 연산자처럼 일반적인 하위 식 제거 및 루프 최적화의 적용을받을 수 있습니다. 이 함수는 pure 속성으로 선언해야합니다.

위의 설명과 일치하지 않는 부작용이있는 기능에 __attribute__((__pure__))을 첨부하면 어떻게됩니까? 함수가 원하는 것보다 적은 횟수 만 호출되거나 정의되지 않은 동작이나 다른 심각한 문제를 만들 수있는 가능성이 있습니까?

마찬가지로 다시 엄격 __attribute__((__const__))을위한 - 문서 상태 : 함수가 전역 메모리를 읽을 수 없기 때문에

기본적으로이 단지 약간 아래의 순수한 속성보다 더 엄격한 클래스입니다.

하지만 글로벌 메모리에 액세스 않는 함수에 __attribute__((__const__))를 연결하면 어떻게 실제로이 일어날 수 있습니까?

정의되지 않은 동작이 언급 될 때마다 나타나는 일반적인 "nasal demons"핸드 웨이빙 대신 GCC/G ++의 범위 내에서 실제 가능한 시나리오에 대한 설명과 함께 기술 답변을 선호합니다.

+3

컴파일러에 거짓말을하면 . –

+0

@Jonathan Leffler는 Babbage가 묻는 질문이 잘못된 경우 "엔진"이 적절한 대답을 줄지 묻는 사람들에 대해 인용합니다. – Swift

답변

1

하지만, 을 위의 설명과 일치하지 않으며, 부작용이 않는 함수에 __attribute__((__pure__)) 을 첨부 할 경우 어떤 일이 일어날 수 있습니까?

정확히. 여기에 간단한 예제입니다 : GCC의

extern __attribute__((pure)) int mypure(const char *p); 

int call_pure() { 
    int x = mypure("Hello"); 
    int y = mypure("Hello"); 
    return x + y; 
} 

내 버전 (4.8.4)는 (결과가 2*mypure()입니다) mypure에 두 번째 통화를 제거 할만큼 영리하다. mypureprintf 인 경우 상상해보십시오 - 인쇄 문자열 "Hello"의 부작용이 사라집니다. 제가

char s[]; 

int call_pure() { 
    int x = mypure("Hello"); 
    s[0] = 1; 
    int y = mypure("Hello"); 
    return x + y; 
} 

call_pure으로 교체하면 (s[0]에 할당 mypure의 출력 값을 변경할 수 있으므로) 모두 호출 출사되도록

참고.

은 함수가 당신이 원하는 것보다 적은 시간 를 호출 할 것을 단순히 가능성, 또는 정의되지 않은 동작 또는 심각한 문제의 다른 종류를 만들 수 있습니다?

음, 간접적으로 UB가 발생할 수 있습니다. 예 : 여기

extern __attribute__((pure)) int get_index(); 

char a[]; 
int i; 
void foo() { 
    i = get_index(); // Returns -1 
    a[get_index()]; // Returns 0 
} 

컴파일러는 대부분 (기술적 언더 웰) get_index()에 두 번째 전화를 삭제하고, 버퍼 오버 플로우가 발생할 것이다 -1 제 리턴 값을 사용한다.

하지만 글로벌 메모리에 액세스 않는 함수에 __attribute__((__const__)) 을 첨부 할 경우 실제로 어떤 일이 일어날 수 있습니까?

하자 다시 mypure__attribute__((const))로 주석했다

int call_pure() { 
    int x = mypure("Hello"); 
    s[0] = 1; 
    int y = mypure("Hello"); 
    return x + y; 
} 

경우에 위의 예를 취할를, 컴파일러는 다시 두 번째 전화를 드롭 2*mypure(...)에 수익을 최적화합니다. mypure이 실제로 s을 읽으면 잘못된 결과가 생성됩니다.

편집

난 당신이 손을 흔들며 방지하기 위해 요청하지만, 여기에 몇 가지 일반적인 설명은 알고있다. 기본적으로 함수 호출은 임의의 부작용 (전역 변수 수정 등)이있는 블랙 박스로 처리되어야하므로 컴파일러 내부에서 많은 최적화를 차단합니다. annotating function을 const 또는 pure 대신에 사용하면 컴파일러는 더 적극적인 최적화를 허용하는 표현식처럼 취급 할 수 있습니다.

예제가 너무 많아서 제공 할 수 없습니다. 위에서 주어진 것은 일반적인 서브 표현식 제거이지만 루프 불변 값, 데드 코드 제거, 앨리어스 분석 등의 이점을 쉽게 입증 할 수 있습니다.

+0

자세한 답변을 보내 주셔서 감사합니다. 그래도이 정보에 대한 언급이 있습니까? 귀하의 설명을 올바르게 이해하고 있다면 순수한 속성과 기본 속성이 기본적으로 중복 된 호출을 제거하는 것과 같은 효과가 있음을 제안하는 것입니다. 그렇다면 const 함수에서 전역 메모리에 액세스하는 데 제한이 있으며 왜 가능한 결과가 발생할 수 있습니까? 나는 실제로 gcc가 이러한 속성들을 어떻게 처리하는지에 대한 세부 사항에 관심이 있습니다 (문서가이 주제에 대해 드문 것처럼). – Riot

+0

@Riot 나는 이것에 대한 철저한 문서를 찾을 수 없을 것이라고 생각합니다. GCC의 많은 최적화 패스는 const/pure 정보를 고려합니다 (루프 인바 리언트, 데드 코드 제거 등을 포함하여 소스를 바탕으로 중간 엔드에 38 개의 파일이 생깁니다). 기본적으로 pure/const 속성은 컴파일러에 부작용이 없으므로 엄청난 양의 최적화에 사용될 수 있음을 알려줍니다. 나는 이것들에 대한 간단한 예를 하나만 들었다. 일반적인 하위 표현식 제거 (고전적 최적화 기법)이다. – yugr

+0

@Riot "const 함수에서 전역 메모리에 액세스하는 이유는 무엇입니까?"- 제약 조건이 아니라 const 함수에 대한 호출을 최적화하는 데 도움이되는 컴파일러에 대한 힌트 잠재적으로 전역 메모리를 수정할 수 있습니다). 다시 말하지만 예제는 실제로 너무 많아 기본적으로 const/pure 속성의 이점을 누릴 컴파일러 최적화는 없습니다. – yugr