Namespaces
Variants

Order of evaluation

From cppreference.net

C 연산자의 피연산자 평가 순서, 함수 호출 표현식에서 함수 인자의 평가 순서, 그리고 모든 표현식 내 하위 표현식들의 평가 순서는 명시되지 않습니다 (아래에 명시된 경우를 제외하고). 컴파일러는 어떤 순서로든 이를 평가할 수 있으며, 동일한 표현식이 다시 평가될 때 다른 순서를 선택할 수 있습니다.

C에는 왼쪽에서 오른쪽으로 또는 오른쪽에서 왼쪽으로의 평가 개념이 존재하지 않으며, 이는 연산자의 왼쪽에서 오른쪽 및 오른쪽에서 왼쪽 결합성과 혼동해서는 안 됩니다: 표현식 f1 ( ) + f2 ( ) + f3 ( ) ( f1 ( ) + f2 ( ) ) + f3 ( ) 로 파싱됩니다. 이는 operator + 의 왼쪽에서 오른쪽 결합성 때문이지만, 런타임에 f3 ( ) 함수 호출은 첫 번째, 마지막, 또는 f1 ( ) f2 ( ) 사이에 평가될 수 있습니다.

목차

정의

평가

컴파일러는 각 표현식 또는 하위 표현식에 대해 두 종류의 평가를 수행합니다(둘 다 선택 사항임):

  • 값 계산(value computation)  : 표현식이 반환하는 값을 계산하는 과정. 여기에는 객체의 정체성 결정( lvalue 평가 )이나 이전에 객체에 할당된 값 읽기(rvalue 평가)가 포함될 수 있습니다.
  • 부작용(side effect)  : volatile lvalue로 지정된 객체에 대한 접근(읽기 또는 쓰기), 객체 수정(쓰기) , atomic 동기화 (C11부터) , 파일 수정, 부동 소수점 환경 수정(지원되는 경우), 또는 위 작업들을 수행하는 함수 호출.

표현식에 의해 부작용이 발생하지 않고 컴파일러가 값이 사용되지 않음을 확인할 수 있는 경우, 해당 표현식은 평가되지 않을 수 있습니다 .

순서

Sequenced-before 는 동일한 스레드 내에서의 평가들 사이의 비대칭적, 추이적, 쌍대적 관계입니다(원자 타입과 메모리 배리어가 관련된 경우 여러 스레드에 걸쳐 확장될 수 있습니다).

  • 만약 시퀀스 포인트 가 하위 표현식 E1 E2 사이에 존재한다면, E1 의 모든 값 계산과 부수 효과는 E2 의 모든 값 계산과 부수 효과보다 선행 시퀀스 됩니다.
  • 평가 A가 평가 B보다 먼저 순서화(sequenced before)되면, A의 평가는 B의 평가가 시작되기 전에 완료됩니다.
  • A가 B보다 먼저 순서화되지 않고 B가 A보다 먼저 순서화되면, B의 평가는 A의 평가가 시작되기 전에 완료됩니다.
  • A가 B보다 먼저 순서화되지 않고 B가 A보다 먼저 순서화되지 않으면, 두 가지 가능성이 존재합니다:
    • A와 B의 평가는 비순서화(unsequenced)됨: 어떤 순서로든 수행될 수 있으며 중첩될 수 있습니다(단일 실행 스레드 내에서 컴파일러는 A와 B를 구성하는 CPU 명령어들을 인터리브할 수 있습니다)
    • A와 B의 평가는 불확정 순서(indeterminately-sequenced)됨: 어떤 순서로든 수행될 수 있지만 중첩될 수 없습니다: A가 B보다 먼저 완료되거나, B가 A보다 먼저 완료됩니다. 동일한 표현식이 다음에 평가될 때 순서가 반대일 수 있습니다.
(C11부터)

규칙

1) 모든 함수 인자와 함수 지정자의 평가 후, 그리고 실제 함수 호출 전에 시퀀스 포인트가 존재합니다.
2) 다음 이항 연산자의 첫 번째(왼쪽) 피연산자 평가 후와 두 번째(오른쪽) 피연산자 평가 전에 시퀀스 포인트가 존재합니다: && (논리 AND), || (논리 OR), 그리고 , (쉼표 연산자).
3) 조건부 연산자 ?: 의 첫 번째(왼쪽) 피연산자 평가 후, 그리고 두 번째 또는 세 번째 피연산자(평가되는 것) 평가 전에 시퀀스 포인트가 존재합니다
4) 전체 표현식(하위 표현식이 아닌 표현식: 일반적으로 세미콜론으로 끝나거나 제어문 if / switch / while / do )의 평가 후와 다음 전체 표현식 전에 시퀀스 포인트가 존재합니다.
5) 완전 선언자(declarator)의 끝에 시퀀스 포인트가 존재합니다.
6) 라이브러리 함수의 반환 직전에 시퀀스 포인트가 존재합니다.
7) 형식화된 입출력에서 각 변환 지정자(conversion specifier)와 연관된 동작 이후에 시퀀스 포인트가 존재합니다 (특히, scanf 가 서로 다른 필드를 동일한 변수에 쓰거나, printf % n 를 사용하여 동일한 변수를 여러 번 읽고 수정하는 것이 올바른 형식입니다)
8) 라이브러리 함수 qsort bsearch 에 의해 수행되는 비교 함수 호출의 직전과 직후에 시퀀스 포인트가 존재하며, 비교 함수 호출과 qsort 에 의해 수행되는 관련 객체 이동 사이에도 시퀀스 포인트가 존재합니다.
(since C99)
9) 모든 연산자의 피연산자에 대한 값 계산(값 계산, side-effect는 제외)은 연산자 결과의 값 계산(값 계산, side-effect는 제외)보다 먼저 시퀀스됩니다.
10) 직접 할당 연산자와 모든 복합 할당 연산자의 부수 효과(side effect, 왼쪽 인자의 수정)는 왼쪽 및 오른쪽 인자의 값 계산(값 계산, side effect는 제외) 이후에 시퀀스됩니다.
11) 후위 증가 및 후위 감소 연산자의 값 계산은 해당 부수 효과(side-effect)보다 먼저 시퀀스됩니다.
12) 다른 함수 호출보다 시퀀스되거나 시퀀스되지 않은 함수 호출은 불확정적으로 시퀀스됩니다 (서로 다른 함수 호출을 구성하는 CPU 명령어는 함수가 인라인화된 경우에도 인터리빙될 수 없습니다)
13) 초기화 목록 표현식에서 모든 평가는 불확정적으로 시퀀스됩니다
14) 불확정적으로 시퀀스된 함수 호출과 관련하여, 복합 할당 연산자의 연산 및 증가/감소 연산자의 전위와 후위 형태 모두 단일 평가(single evaluation)입니다.
(since C11)

정의되지 않은 동작

1) 스칼라 객체에 대한 부수 효과가 동일한 스칼라 객체에 대한 다른 부수 효과와 비순서 관계에 있을 경우, 동작은 정의되지 않음 .
i = ++i + i++; // undefined behavior
i = i++ + 1; // undefined behavior
f(++i, ++i); // undefined behavior
f(i = -1, i = -1); // undefined behavior
2) 스칼라 객체에 대한 부수 효과가 동일한 스칼라 객체의 값을 사용하는 값 계산과 비순서 관계에 있을 때, 그 동작은 정의되지 않습니다.
f(i, i++); // undefined behavior
a[i] = i++; // undefined behavior
3) 위 규칙들은 하위 표현식들의 적어도 하나의 허용 가능한 순서가 그러한 비순차 부수 효과를 허용하는 한 적용됩니다.

참고 항목

연산자 우선순위 는 표현식이 소스 코드 표현으로부터 어떻게 구성되는지를 정의합니다.

C++ 문서 참조: 평가 순서