IT TIP

C ++에서 컴파일러 및 인수 평가 순서

itqueen 2020. 12. 12. 12:52
반응형

C ++에서 컴파일러 및 인수 평가 순서


좋아, 나는 표준이 C ++ 구현이 함수의 인수가 평가되는 순서를 선택할 수 있다고 지시한다는 것을 알고 있지만 실제로 프로그램에 영향을 미치는 시나리오에서 이것을 실제로 '활용'하는 구현이 있습니까?

전형적인 예 :

int i = 0;
foo(i++, i++);

참고 : 평가 순서를 신뢰할 수 없다고 말하는 사람을 찾는 것이 아닙니다. 잘 알고 있습니다. 나는 어떤 컴파일러가 실제로 왼쪽에서 오른쪽 순서로 평가하는지 여부에만 관심이 있습니다. 왜냐하면 내 추측은 그들이 잘못 작성된 코드를 많이 수행하면 손상 될 것이라고 생각하기 때문입니다 (올바르게 작성되었지만 여전히 불평 할 것입니다).


인수 유형, 호출 된 함수의 호출 규칙, 아키텍처 및 컴파일러에 따라 다릅니다. x86에서 Pascal 호출 규칙은 인수를 왼쪽에서 오른쪽으로 평가하는 반면 C 호출 규칙 ( __cdecl )에서는 오른쪽에서 왼쪽입니다. 여러 플랫폼에서 실행되는 대부분의 프로그램은 놀라움을 건너 뛰기 위해 호출 규칙을 고려합니다.

관심이 있다면 Raymond Chen의 블로그에 멋진 기사 가 있습니다. GCC 매뉴얼 스택 및 호출 섹션을 살펴볼 수도 있습니다.

편집 : 우리가 머리카락을 나누는 한 : 내 대답은 이것을 언어 질문이 아니라 플랫폼 질문으로 취급합니다. 언어 표준은 다른 것보다 하나를 보장하거나 선호하지 않으며 지정되지 않은 상태로 둡니다 . 문구에 유의하십시오. 이것이 정의되지 않았다고 말하는 것은 아닙니다. 이 의미에서 지정되지 않음은 신뢰할 수없는 이동 불가능한 동작을 의미합니다. 편리한 C 사양 / 초안이 없지만 n2798 초안 (C ++)과 비슷해야합니다.

추상 기계의 특정 다른 측면과 작동은이 국제 표준에서 지정되지 않은 것으로 설명되어 있습니다 (예 : 함수에 대한 인수 평가 순서). 가능한 경우이 국제 표준은 허용 가능한 행동 세트를 정의합니다. 이것들은 추상 기계의 비 결정적 측면을 정의합니다. 따라서 추상 기계의 인스턴스는 주어진 프로그램과 주어진 입력에 대해 둘 이상의 가능한 실행 순서를 가질 수 있습니다.


나는 C ++ 표준 에서 답을 찾았습니다 .

5.2.2.8 절 :

인수 평가 순서는 지정되지 않습니다. 인수 표현식 평가의 모든 부작용은 함수가 입력되기 전에 적용됩니다. 접미사 식과 인수 식 목록의 평가 순서는 지정되지 않습니다.

즉, 컴파일러에만 의존합니다.


이것을 읽으십시오

귀하의 질문의 정확한 사본은 아니지만 내 답변 (및 기타 몇 가지)도 귀하의 질문을 다룹니다.

컴파일러가 오른쪽에서 왼쪽으로 선택하는 것이 아니라 인터리빙 할 수있는 매우 좋은 최적화 이유가 있습니다.

표준은 순차 주문도 보장하지 않습니다. 그것은 단지 함수가 호출 될 때, 모든 인수가 완전히 평가 된 것을 보장합니다.

그리고 네, GCC의 몇 가지 버전이 정확히 이것을 수행하는 것을 보았습니다. 예를 들어 foo (0,0)이 호출되고 나중에 i가 2가됩니다. (컴파일러의 정확한 버전 번호를 알려 드릴 수 없습니다. 얼마 전 이었지만이 동작이 다시 나타나는 것을보고 놀라지 않을 것입니다. 명령을 예약하는 효율적인 방법입니다)


모든 인수가 평가됩니다. 주문이 정의되지 않았습니다 (표준에 따라). 그러나 C / C ++의 모든 구현 (내가 알고있는)은 오른쪽에서 왼쪽으로 함수 인수를 평가합니다 . 편집 : CLang은 예외입니다 (아래 설명 참조).

나는 오른쪽에서 왼쪽으로의 평가 순서가 매우 오래되었다고 생각합니다 (첫 번째 C 컴파일러 이후). 확실히 C ++가 발명되기 전에는 초기 C ++ 구현이 단순히 C로 번역되기 때문에 대부분의 C ++ 구현은 동일한 평가 순서를 유지합니다.

함수 인수를 오른쪽에서 왼쪽으로 평가하는 데에는 몇 가지 기술적 이유가 있습니다. 스택 아키텍처에서 인수는 일반적으로 스택으로 푸시됩니다. C / C ++에서는 실제로 지정된 것보다 더 많은 인수를 사용하여 함수를 호출 할 수 있습니다. 추가 인수는 간단히 무시됩니다. 인수가 왼쪽에서 오른쪽으로 평가되고 왼쪽에서 오른쪽으로 밀면 스택 포인터 아래의 스택 슬롯이 마지막 인수를 보유하고 함수가 특정 인수의 오프셋에서 얻을 수있는 방법이 없습니다. (푸시되는 실제 인수 수는 호출자에 따라 다르기 때문입니다).

오른쪽에서 왼쪽으로 밀어 넣기 순서에서 스택 포인터 바로 아래의 스택 슬롯은 항상 첫 번째 인수를 보유하고 다음 슬롯은 두 번째 인수 등을 보유합니다. 인수 오프셋은 항상 함수에 대해 결정적입니다 (쓰기 및 호출 된 곳과는 별도로 다른 곳에서 라이브러리로 컴파일 됨).

이제 오른쪽에서 왼쪽 푸시 순서는 오른쪽에서 왼쪽으로 평가 순서를 요구하지 않지만 초기 컴파일러에서는 메모리가 부족합니다. 오른쪽에서 왼쪽으로의 평가 순서에서 동일한 스택을 제자리에서 사용할 수 있습니다 (본질적으로 인수를 평가 한 후-표현식 또는 함수 호출 일 수 있습니다!-반환 값은 이미 오른쪽 위치에 있습니다. 스택). 왼쪽에서 오른쪽으로 평가할 때 인수 값은 별도로 저장해야하며 역순으로 스택에 푸시해야합니다.


지난번에 2007 년 x86 하드웨어에서 VS2005와 GCC 3.x의 차이점을 확인했습니다. 그래서 그것은 매우 가능성이 높은 상황입니다. 그래서 더 이상 평가 순서에 의존하지 않습니다. 지금은 더 나을 수도 있습니다.


나는 대부분의 현대 컴파일러가 인수를 계산하는 명령어를 인터리빙하려고 시도 할 것으로 예상한다. C ++ 표준에서 독립적이어야하기 때문에 상호 의존성이 부족하다는 점을 감안할 때. 이렇게하면 깊이 파이프 라인 된 CPU의 실행 단위를 가득 채우고 처리량을 늘리는 데 도움이됩니다. (적어도 최적화 컴파일러라고 주장하는 컴파일러는 최적화 플래그가 주어지면 그렇게 할 것이라고 기대합니다.)

참고 URL : https://stackoverflow.com/questions/621542/compilers-and-argument-order-of-evaluation-in-c

반응형