2013-07-30 2 views
1

나는 이성적인 문제를 발견하지 못했다. 문제는 for (i = size - 1; i >= 0; i--) {etc.}에 대한 for 루프 내부에있는 것 같습니다. 여기서 size은 메모리 버퍼에 저장된 파일의 크기이고 i은 부호없는 정수입니다. i == 0이 멈 추면 멈추지 않고 i = 4294967295이되어 세그멘테이션 오류가 발생합니다. 조건부를 i > 0으로 변경하면 문제가 해결됩니다.이상한 동작을위한 C for 루프

그러나 이런 특별한 종류가 아닙니까? for 루프가 C로 어떻게 작동하는지에 대한 중요한 부분을 놓치고 있어야합니다. 초기화, 조건부 검사, 증분/감소, 조건부 검사 등을 따르지 않습니까?

도움을 주시면 감사하겠습니다.

+5

"i"는 부호없는 int이므로 0보다 크다. –

+3

거의 없지만 @RaghuSrikanthReddy. – Bart

+0

@ Bart의 의견은 약간 정확하지 않은 경우 정확합니다. 그는'나는'unsigned int'라는 이유로 항상''''와 같거나''0 ''보다 크다는 것을 확신합니다. Raghu가 말한 것과 거의 비슷합니다. – ravron

답변

8

부호없는 정수는 항상 >= 0입니다. iunsigned int 경우

for (i = size - 1; i >= 0; i--) {etc.} 

무한 루프이다.

+0

그게 내 말은? 내가 값 0을 가지고 i가 호출 될 때 그 자체가 감싸는 것을 의미합니까? – ckv

+0

@ckv 'i'가 '0'일 때 'i - 1'값은 양수인 'UINT_MAX'와 같습니다. – ouah

+0

그래서, 그것이 멈추지 않는 이유입니다. '나는 결코 부정적이되지 않는다 ... 나는 너무 바보 같다. : D 대단히 감사합니다! – someone

2

i0에 접근하면 어떻게되는지 봅시다.

  • i == 1 : 루프는 i >= 0 이후 정상적으로 실행됩니다. i에서 1을 뺍니다. 지금 i은 0을 포함합니다.
  • i == 0 : 루프는 i >= 0 이후 정상적으로 실행됩니다. i에서 1을 뺍니다. i은 서명이 없으므로 랩 어라운드가됩니다. 따라서, i 지금 4294967295
  • i == 4294967295 다음이 포함 루프는

솔루션은 뭔가 다른 테스트 중이다 ... 등등 i >= 0

  • 하고 있기 때문에 일반적으로 실행 (예 : i > 0와 같은, 당신의 예와 같이) 또는 파일의 크기보다 작 으면 모든 반복 및 반복마다 i을 증가 시키십시오. C99 표준에 따라

  • +0

    먼저 증가/감소 작업을 수행하고 확인하지 않습니까? 보통 for-loop (즉,'i ++')에서 조건문이'i <= size' 일 때 마지막 반복은'i == size'이고 종료 할 때는'i == size + 1'입니다. – someone

    +0

    천사 : 정확합니다. 그러나 이것은 설명과 관련이 없습니다. 조건 확인은 항상 감소가 뒤 따르고 감소는 항상 (우리가 편리하게 루프 본문을 잊어 버린 경우) 조건 점검에 따라옵니다. –

    +0

    네, 사실 저는 바보로 잘못된 것을 확인한 것입니다! 당신 말이 맞아요, 그것이 음수가 될 수 없으며 무한히 감에 따라 감싼다. 나는 그것을 다음과 같이 변경하여 고쳤다 : for (i = size - 1; i someone

    1

    :

    6.2.5 유형

    9) [...] 수 절대 오버플 부호 피연산자 관련 된 계산은 결과 때문에 표현할 수없는 결과 부호없는 정수 유형은 결과 유형으로 나타낼 수있는 최대 값보다 하나 큰 숫자를 모듈로 감소시킵니다.

    그래서, 여기 당신의 경우에 일어나는 내용은 다음과 같습니다

    • i == 1 따라서 i == 0에서 i-- 결과.
    • i == 0이므로 i--이 랩 어라운드되고 i == UINT_MAX이됩니다.
    • i == UINT_MAX이므로 i--i == UINT_MAX - 1이됩니다. 루프를 고정

    한 가지 방법은 다음 (https://stackoverflow.com/a/665773/676939)를 사용하는 것입니다 :

    for (i = size; i-- > 0;){ 
        /* yada yada yada */ 
    } 
    

    같은 일을하는 또 다른 방법은 다음 (https://stackoverflow.com/a/665758/676939)입니다 : 부호에서

    unsigned fake_i; 
    for (fake_i = size; fake_i > 0; i--){ 
        unsigned i = fake_i - 1; 
        /* Do something with i */ 
    } 
    
    1

    가장 중요한 비트는 부호 비트로 취급되지 않습니다. 귀하의 경우 부호없는 int는 4bytes(32 bits)입니다.

    따라서 '0'을 감소시킬 때 2's complement1 인 방법은 0에 추가됩니다. 어느 쪽이 4294967295이고, 모든 32 비트가 1 일 때 아무것도 아닌 최대 값입니다. 따라서 4294967295 결과입니다.

    최대 값 4294967295에서 증가하는 동안 (즉, 32 비트가 모두 1 일 때) 이 값이 증가하면 하위 32 비트가 모두 0으로되고 32nd 비트가 1로 설정됩니다. 따라서 부호없는 int에 대해 4 바이트 범위를 벗어나는 32nd 비트에 오버플로가 있습니다. 따라서 값은 0이됩니다.

    일반적으로 부호없는 유형의 경우는 0....MaxValue에서 줄 바꿈됩니다. MaxValue 이상으로 증가 할 경우 0에서 다시 입력하십시오. 0 이하로 감소하면 MaxValue에서 다시 입력합니다.

    +0

    답변 해 주셔서 감사합니다! : D 문제는 이미 해결되었지만 ... :) – someone