2016-10-31 6 views
7

다음과 같은 코드로 인해 산술 오버 플로우의 정의되지 않은 동작을 호출하는 것이 분명 보인다i ++는 오버플로의 경우 int보다 작은 서명 된 유형에 대해 정의되지 않은 동작을 호출합니까?

#include <limits.h> 

int test(void) { 
    int i = INT_MAX; 
    i++; /* undefined behavior */ 
    return i; 
} 

그러나보다 작은 서명 유형에 대한 int 같은 short 또는 signed char로? (더 작게, 각각 SCHAR_MAX < INT_MAXSHRT_MAX < INT_MAX이라고 가정).

다음 중 정의되지 않은 동작을 호출하는 함수는 무엇입니까? 그 이유는 무엇입니까?

signed char test2(void) { 
    signed char i = SCHAR_MAX; 
    i = i + 1; /* implementation defined */ 
    return i; 
} 

signed char test3(void) { 
    signed char i = SCHAR_MAX; 
    i += 1; /* undefined behavior or implementation defined? */ 
    return i; 
} 

signed char test4(void) { 
    signed char i = SCHAR_MAX; 
    i++;  /* undefined behavior or implementation defined? */ 
    return i; 
} 

signed char test5(void) { 
    signed char i = SCHAR_MAX; 
    ++i;  /* undefined behavior or implementation defined? */ 
    return i; 
} 

추론을 뒷받침하는 참조 자료를 제공하거나 인용하십시오.

signed char i = SCHAR_MAX; 
i++; 

운영자 접미사가 ++ 정수 프로모션 또는 일반적인 산술 변환 1을 수행하지 않습니다

+3

부호있는 정수는 내부 형식과 크기에 관계없이 부호있는 정수입니다. 그러나 'test2'에있는 경우 예를 들어 'int j = i + 1;'그렇다면'i'는 [* promoted *] (http://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion)에서 'int'. –

+0

내가 ++로 정의되지 않은 행동을하게 만든 이유는 무엇입니까? 나는 그 행동이 잘 정의되어 있다고 생각했다. –

+2

@DonghuiZhang 부호있는 정수 오버 플로우가 "필수"가 아닙니다. –

답변

0

다음 코드는 원인과 오버 플로우 때문에 정의되지 않은 동작을 수행합니다. 연산자는 피연산자의 값에 1을 더한다. . 작업이 오버플로됩니다.

명확한 구분이 단항 산술 연산자의 문구에서 유래 : 문구가 명확하게 피연산자가 3 승진되어 있다고하는 +, -, ~을. 그러나 접미사 ++ 연산자에 대한 표현은 연산자가 승진되었다고하지 않습니다 .

분명히 postfix ++ 연산자는 피연산자를 승격하지 않습니다.


1, 일반적인 산술 변환의 일부로서, (: ISO/IEC 9899 :에서 인용은 201x는 6.3.1.1 부울, 문자 및 정수 2 58))
정수 프로모션에만 적용 특정 인수 표현식에 대한 단항 +, - 및 ~ 연산자의 피연산자와 각각의 하위 절에 지정된대로 시프트 연산자의 두 피연산자에 대한 값을 반환합니다. 부작용으로
는 피연산자 객체 값이 증가된다 (즉, 값이 1 인

2 을 (: ISO/IEC 9899 201x 6.5.2.4 후위 증감 연산자 2에서 인용) ISO/IEC 9899 : 가 추가되어 적절한 유형)의

3

은 (상기 인용 201x 6.5.3.3 단항 연산기 2)
단항 + 연산자의 결과의 값을 그 (승격 됨) 피연산자. 정수 프로모션이 피연산자에 대해 수행되고 결과에 수준이 올라갑니다.

4 (: ISO/IEC 9899 : 6.5.2.4에서 인용 201x 후위 증가 및 감소 연산자 2)
후위의 결과 ++ 연산자 피연산자의 값이다.

+1

@BaummitAugen 인용문 "표현식을 평가하는 동안 결과가 수학적으로 정의되지 않았거나 해당 유형의 표현 가능한 값 범위에 있지 않으면 동작은 정의되지 않습니다." "결과 유형이 [정의되지 않은 행동 유도와 관련하여] 산술이 수행되는 유형과 직각이라는 귀하의 주장을 예시하지 않습니다. –

+0

@ user694733 시퀀스 포인트는 평가의 크기와 아무 관련이 없습니다. '인수'는 승진 한 후 마지막 sizeof 평가가 실제로 피연산자 크기를 산출하기 때문에 자기 모순입니다. – 2501

+0

@BaummitAugen 일반적인 산술 프로모션은 지정된 경우에만 적용되며 그렇지 않은 경우 적용되지 않습니다.Postfix ++는 그 (것)들이 적용하는 것을 지정하지 않는다, 그래서 그들은하지 않는다. 비록 비 규범적인 각주와 실제적인 예제를 무시했다하더라도, 단항 피연산자가 피연산자를 승격시키고 다른 피연산자는 승격시키지 않는다는 것을 보여주는 표준으로부터의 두 개의 규범적인 인용 부호 (당신이 잊었던)가 여전히 존재합니다. – 2501

4

+= 및 유사한 연산자가 대상 유형의 값과 실제로 수행하는 많은 구현에서 직접 연산하는 것이 논리적 일 것입니다. 그러나 표준에서는 대상의 값이 적용 가능한 표준 및 균형 조정 프로모션을 거친 다음 지정된 작업을 처리 한 다음 대상 유형으로 다시 변환되는 것처럼 운영자가 작동하도록 요구합니다.

결과가 32,767을 넘으면, 그것은 양보해야 하나 su 서명 및 부호없는 16 비트 변수 및 int가 32 비트 인 경우 그 결과, 다음 s*=s;s의 모든 값에 대해 정의 될

구현 정의 값을 정의하거나 구현 정의 된 신호를 발생시킵니다. 대부분의 구현은 2의 보수를 줄이기 위해 다른 방법을 사용하지 않아야합니다. 반면에 u*=u;u의 값에 대해 최대 65336을 46340까지만 랩 할 수 있습니다. 큰 값의 경우 정의되지 않은 동작이 호출됩니다.