세 가지 이유가 있습니다.
우선, 1을 오버플 start + (end - start) / 2
로 end - start
하지 않는 한 포인터를 사용하더라도 작동합니다 .
int *start = ..., *end = ...;
int *mid = start + (end - start) / 2; // works as expected
int *mid = (start + end) / 2; // type error, won't compile
둘째로, start + (end - start) / 2
하지 오버 플로우 경우 것입니다 start
및 end
큰 긍정적 인 숫자입니다. 부호있는 피연산자를 사용하면 오버플로가 정의되지 않습니다.
int start = 0x7ffffffe, end = 0x7fffffff;
int mid = start + (end - start) / 2; // works as expected
int mid = (start + end) / 2; // overflow... undefined
(이 end - start
경우 오버플로 가 발생할 수 있지만 start < 0
또는 경우에만 해당됩니다 end < 0
.)
또는 부호없는 산술을 사용하면 오버플로가 정의되지만 잘못된 대답을 제공합니다. 그러나 부호없는 피연산자의 경우 start + (end - start) / 2
에는 오버플로되지 않습니다 end >= start
.
unsigned start = 0xfffffffeu, end = 0xffffffffu;
unsigned mid = start + (end - start) / 2; // works as expected
unsigned mid = (start + end) / 2; // mid = 0x7ffffffe
마지막으로, 당신은 종종 start
요소를 향해 반올림하려고합니다 .
int start = -3, end = 0;
int mid = start + (end - start) / 2; // -2, closer to start
int mid = (start + end) / 2; // -1, surprise!
각주
1 C 표준에 따르면 포인터 빼기 결과를로 표현할 수없는 ptrdiff_t
경우 동작이 정의되지 않습니다. 그러나 실제로 char
는 전체 주소 공간의 절반 이상을 사용하여 배열을 할당해야 합니다.
(start + end)
넘칠(end - start)
수는 있지만 넘칠 수는 없습니다.