Üç sebep var.
Her şeyden önce, 1 taşmadığı start + (end - start) / 2
sürece işaretçiler kullanıyor olsanız bile çalışır .end - start
int *start = ..., *end = ...;
int *mid = start + (end - start) / 2; // works as expected
int *mid = (start + end) / 2; // type error, won't compile
İkincisi, start + (end - start) / 2
değil taşması durumunda olacak start
ve end
büyük pozitif sayılardır. İmzalı işlenenlerde taşma tanımsız:
int start = 0x7ffffffe, end = 0x7fffffff;
int mid = start + (end - start) / 2; // works as expected
int mid = (start + end) / 2; // overflow... undefined
(Taşınabileceğini unutmayın end - start
, ancak yalnızca start < 0
veya end < 0
.
Veya imzasız aritmetik ile taşma tanımlanır, ancak yanlış cevap verir. Ancak, imzasız işlenenler için start + (end - start) / 2
asla taşmadığı sürece end >= start
.
unsigned start = 0xfffffffeu, end = 0xffffffffu;
unsigned mid = start + (end - start) / 2; // works as expected
unsigned mid = (start + end) / 2; // mid = 0x7ffffffe
Son olarak, genellikle start
öğeye doğru yuvarlanmak istersiniz .
int start = -3, end = 0;
int mid = start + (end - start) / 2; // -2, closer to start
int mid = (start + end) / 2; // -1, surprise!
Dipnotlar
1 C standardına göre, eğer işaretçi çıkarma sonucu a olarak gösterilemiyorsa ptrdiff_t
, davranış tanımsızdır. Bununla birlikte, pratikte, bu char
, tüm adres alanının en az yarısını kullanarak bir dizi tahsis edilmesini gerektirir .
(start + end)
taşabilir, ancak(end - start)
yapamaz.