2009-03-07 2 views
52

좋아요, 표준에 따르면 C++ 구현에서 함수의 인수가 평가되는 순서를 선택할 수 있지만 실제로이 함수를 '활용하는'구현이 있는지를 알 수 있습니다 실제로 프로그램에 영향을 미칠 시나리오에서?C++에서의 컴파일러와 인수 순서

클래식 예 :

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

참고 : 나는 평가의 순서에 의존 할 수 없음을 말해 줄 사람을 찾는 게 아니에요, 나는 그 잘 알고 있어요. 나는 컴파일러가 실제로 왼쪽에서 오른쪽 순서로 평가하는지 여부에만 관심이있다. 왜냐하면 저조한 코드가 많이 나왔다면 (맞을 것이지만 여전히 불평 할 것이지만) 내 생각에 그렇게 될 것이기 때문이다.

+0

다른 컴파일러로 직접 시도해보십시오. – strager

+0

C++의 하위 집합에 대한 인터프리터를 구현하는 동안 동일한 질문을 던졌습니다. 휴. –

+6

'foo (i ++, i ++)'는 정의되지 않은 동작을 호출합니다. 왜냐하면'i'는 하나 이상의 시퀀스 포인트를 개입시키지 않고 하나 이상 증가하기 때문입니다. – Nawaz

답변

49

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

관심이 있으시면 레이몬드 첸 (Raymond Chen) 블로그에 article이라는 멋진 글이 있습니다. GCC 매뉴얼의 Stack and Calling 섹션을 살펴볼 수도 있습니다.

편집 : 우리가 머리카락을 나눌 때까지 : 내 대답은 이것을 언어 문제가 아니라 플랫폼 문제로 간주합니다. 언어 표준은 다른 것보다 하나를 선호하거나 선호하지 않으며 으로 지정되지 않은으로 남습니다. 말씨에 유의하십시오. 이것이 정의되지 않는다고 말하는 것은 아닙니다. 이 의미에서 지정되지 않은 것은 당신이 믿을 수없는 무언가, 비 휴대용 행동을 의미합니다. (이는 내가 편리한은 C 사양/초안을하지 않아도하지만 추상 기계의

어떤 다른 측면과 운영이 지정되지 않은 등이 국제 표준에 설명되어 내 n2798 초안 (C++)에서 유사해야한다 예를 들어, 함수에 대한 인수의 평가 순서). 가능한 경우,이 국제 표준은 허용 가능한 일련의 행동을 정의한다. 이것들은 추상 기계의 비 결정적 측면을 정의합니다. 따라서 추상 기계의 인스턴스는 주어진 프로그램 및 주어진 입력에 대해 둘 이상의 가능한 실행 순서를 가질 수 있습니다.

+11

pascal/cdecl은 인수가 왼쪽에서 오른쪽으로 또는 오른쪽에서 왼쪽으로 전달되었는지 여부를 결정합니다. 이는 순서에 관계없이 * 평가할 수 있습니다. (레지스터 압박 때문에 통과 한 순서대로 평가 될 가능성이 높습니다.) –

+8

Wrong : C 인수가 오른쪽에서 왼쪽으로 스택에 푸시됩니다. 그러나 평가 된 순서는 정의되지 않았습니다. –

+1

@Martin York : 언제 명령이 잘 정의되어 있다고 말했습니까? – dirkgently

1

지난 번에 x86 하드웨어에서 VS2005와 GCC 3.x의 차이점을 알았습니다. 그래도 그럴 가능성이 매우 높습니다. 따라서 평가 순서에 더 이상 의존하지 않습니다. 어쩌면 더 좋을지도 몰라.

+0

오? 그것은 아주 잘 알고 있습니다. 감사. 현재 내가 사용하는 컴파일러는 VC 08과 ICC 11뿐입니다. GCC에서도 코드를 테스트해야합니다. – RaptorFactor

+2

ICC는 가능한 한 VS와 호환되도록 아주 오래갑니다. 좋은 사람들은 Intel 사람들입니다. –

+0

VS는 평가판을 보증하지 않습니다. 그들은 이전에 함수 인수를 평가하는 방법을 변경했으며, 그렇게하지 않을 이유가 없습니다. 그것은 당신이 의존해야하는 것이 아닙니다. – jalf

2

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

6

Read this

그것은, 질문의 정확한 복사본 아니지만 내 대답 (그리고 몇몇 다른 사람)는 당신의 질문을 또한 커버합니다.

컴파일러가 오른쪽에서 왼쪽으로 선택하고 인터리빙 할 수있는 최적의 이유가 있습니다.

이 표준은 순차적 순서 지정을 보장하지 않습니다. 은 함수가 호출 될 때 모든 인수가 완전히 평가되었음을 보증합니다.

그리고 네, GCC의 몇 가지 버전이 이와 똑같은 것을 보았습니다. 귀하의 예를 들어, foo (0,0), 그리고 호출 될 것이라고 나는 2 후 것입니다. (필자는 컴파일러의 정확한 버전 번호를 알려주지 못했습니다. 이전 버전 이었지만이 동작이 다시 나타나는지는 놀랄 일이 아닙니다. 지침을 효율적으로 작성하는 방법입니다)

+0

일반 하위 식 제거가 최적화 순서 재 지정의 주된 이유입니다. 인수 평가와 매개 변수 전달은 많은 컴파일러가 동일하게 처리하더라도 서로 다를 수 있음을 기억하십시오. – plinth

3

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

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

오른쪽에서 왼쪽으로 함수 인수를 평가하는 몇 가지 기술적 인 이유가 있습니다. 스택 아키텍처에서 인수는 일반적으로 스택에 푸시됩니다. C/C++에서는 실제로 지정한 것보다 많은 인수를 가진 함수를 호출 할 수 있습니다. 추가 인수는 무시됩니다. 인수가 왼쪽에서 오른쪽으로 평가되고 왼쪽에서 오른쪽으로 밀어 넣으면 스택 포인터 바로 아래의 스택 슬롯에 마지막 인수가 저장되며 함수가 특정 인수의 오프셋에서 가져올 방법이 없습니다 (실제로 전달되는 인수의 개수는 호출자에 따라 다르므로).

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

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

+0

clang은 왼쪽에서 오른쪽으로 평가를 사용합니다. – Kaiserludi

8

c++ standards에 답변을 찾았습니다.

단락 5.2.2.8 : 인수의 평가

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

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

+2

음, 질문에 응답하지 않습니다. – ThomasMcLeod