2010-07-24 4 views
9

나는표현식의 동작 : 정의 또는 정의되지 않음?

int m[4]={1,2,3,4}, *y; 
y=m; 
*y = f(y++); // Expression A 

내 친구가 Expression A가 잘 정의 된 동작을 가지고 있지만 나는 그가 맞는지 확실하지 않다 저에게 다음과 같은 코드가 있습니다.

그의 기능에 따르면 f()sequence point을 소개하며 따라서 동작이 잘 정의되어 있습니다.

누군가를 분명히하십시오.

p.s : 실용적인 코드를 작성해서는 안됩니다. 그것은 단지 학습의 목적을위한 것입니다. :)

+3

아니요. 그것이 gcc가 말하는 것입니다. – kennytm

답변

15

기껏해야 문제의 코드는 명시되지 않은 동작을합니다. 할당 연산자의 경우 "피연산자에 대한 평가 순서가 지정되지 않았다"(C99 §6.5.16/4).

왼쪽 피연산자가 먼저 계산되면 f(y++)의 결과는 m[0]에 저장됩니다. 오른쪽 피연산자가 먼저 평가되면 결과는 m[1]에 저장됩니다. 행동이 정의되어 있는지 여부에 관해서

는 중요한 항이다 : 객체 표현의 평가가 많아야 한 번 그 저장된 값 수정 된 Fi를 에드 가진다 이전 및 다음 시퀀스 포인트 간의

. 또한, 이전 값은 저장 될 값을 결정하기 위해서만 읽혀 져야한다 (C99 §6.5/2).왼쪽이 먼저 평가하는 경우 순서이기 때문에

는, 우리는 충돌한다 두 번째 문장의 실행

y의 값은 역 참조
  • 받는 왼쪽에 읽어
    1. y 값을 오른쪽에서 읽으면 값이 증가합니다.
    2. 함수에 대한 인수를 평가 한 후에 시퀀스 포인트가 있습니다 (따라서 y++의 부작용이 완료되고 y이 기록됨).

    단계 1에서 "이전 값"이 y이지만 "저장할 값을 결정하는 것"이외의 목적으로 읽습니다. 따라서 하나의 유효한 평가 순서가 정의되지 않은 동작을 산출하기 때문에 동작은 실제로 정의되지 않습니다.

  • +2

    +1. '* y'와'y ++ '의 평가는 순서가 지정되지 않았고 후자는'y'에 부작용을 유발하기 때문에 정의되지 않았습니다. – avakar

    +0

    제임스 감사합니다, 당신의 대답은 완벽합니다. AC :-) –

    0

    편집 : 이것은 잘못되었지만 의견에 나오는 토론이 다소 밝아지기 때문에 여기에 남겨두고 있습니다.

    C (또는 C++) 연산자의 평가 순서에 따라 잘 정의되어 있습니다.

    식의 오른쪽 부분을 먼저 지정하십시오. 함수 응용 프로그램은 먼저 인수에 대한 평가를 강제 실행하므로 효과가 상당히 명확 해 보입니다 (실행하려고 시도하지는 않았으므로 자유롭게 수정하십시오!). 우리는 (나는 T0와 T1을 전화 할게)이 사용하는 임시 변수를 다시 작성할 수 있고, 나는이 좀 더 명확 수 있습니다 믿습니다

    t0 = y++; 
    t1 = f(t0); 
    *y = t1; 
    

    용어 "순서 포인트"붉은 청어의 비트입니다. 시퀀스 포인트는 실제로 생성되지 않고 언어에 대해 엄격한 평가 순서가 정의 된 결과입니다.

    EDIT :이 대답은 지적으로 만족스러운 것처럼 보이지만 James McNellis의 대답은 할당의 평가 순서가 이 아니고이 잘 정의 된 C99 사양의 관련 부분을 인용합니다. 그의 사실을 실제로 확인하기 위해 그에게 완전한 신용. 필자는 "잘 정의 된 것"에서 "특정 컴파일러와 관련하여 정의가 잘되어있을 것"이라는 대답을 수정하려고합니다. 대부분의 컴파일러가 이러한 코드를 내보내는 순서를 정기적으로 바꿀 가능성은 없습니다 (매우 적극적인 최적화를 설명하기 위해 "아마"라고 말합니다.)

    +2

    _Assignment는 먼저 표현식의 오른쪽 부분을 평가합니다. _ 사실이 아닙니다. 평가 순서가 지정되지 않았습니다. –

    +1

    과제의 오른편을 먼저 평가해야한다는 것은 어디까지입니까? – jalf

    +0

    감사합니다. 방금 내 대답을 편집하여 C에 대해 새로운 것을 가르쳐 주셔서 감사합니다. – Gian

    1

    는 표현은 잘 정의되지 않습니다

    식의 유효한 해석은 다음과 같습니다 식의

    (1) int* t0 = y++; 
    (2) int t1 = f(t0); 
    (3) int& t2 = *y; 
    ----------------- 
    t2 = t1; 
    

    동등하게 유효한 해석은 다음과 같습니다

    (1) int& t2 = *y; 
    (2) int* t0 = y++; 
    (3) int t1 = f(t0); 
    ----------------- 
    t2 = t1; 
    

    이 두가 vaalid하고 다른 결과를 생성합니다. 따라서 표현식에는 정의되지 않은 결과가 있습니다.

    +1

    일반적으로 표현식이 두 가지 다른 결과를 가질 수 있다는 사실은 결과가 * 지정되지 않았 음을 의미합니다. 그러나이 특별한 경우에't0'와't2'의 계산은 어떤 순서로도 발생할 수 있고 't0'는'y'에 부작용을 가지고't2'는'y'의 값을 사용하기 때문에 결과는 실제로 정의되지 않습니다. – avakar

    13

    시퀀스 포인트를 소개하는 함수 호출에 대해 절대적으로 맞습니다. 그러나 해당 시퀀스 포인트는 상황에 따라 상황을 저장하지 않습니다.

    먼저 간단한 예를

    i = some_function(i++); 
    

    이 유효인가를 생각해? 예, 그렇습니다. 왜? 함수에 의해 도입 된 시퀀스 포인트가 i의 두 수정을 서로 분리하여 코드를 유효하게 만들기 때문에 유효합니다. 이 표현식에 대한 평가 순서가 없으므로 중재 시퀀스 포인트없이 두 번 수정됩니다 (i).

    그러나,의 순서 지점뿐만 아니라 존재하는이 경우 귀하의 변형

    *y = f(y++); 
    

    로 돌아가 보자. 그러나이 언어는 = 연산자의 평가 순서에 대해 아무런 보증도하지 않습니다. (의미 : 할당 연산자의 피연산자가 왼쪽 또는 오른쪽인지 먼저 평가되지 않습니다. 컴파일러가 먼저 왼쪽 (*y), 함수 인수 (y++)를 평가 한 다음 함수를 호출하고 실제 할당을 수행하는 것이 허용 될 수 있습니다. 이 잠재적 시나리오에서 처음 두 단계 - y 읽기 및 y 수정 -은 시퀀스 포인트에 의해 구분되지 않습니다. 따라서 동작은 정의되지 않습니다.

    +1

    @Ben Voigt :'= '연산자의 피연산자 평가의 상대적 순서, 즉 LHS 또는 RHS가 먼저 평가되는지 여부에 대해 이야기하고있었습니다. – AnT

    관련 문제