Es gibt drei Gründe.
Funktioniert zunächst start + (end - start) / 2
einmal auch, wenn Sie Zeiger verwenden, solange end - start
nicht 1 überläuft .
int *start = ..., *end = ...;
int *mid = start + (end - start) / 2; // works as expected
int *mid = (start + end) / 2; // type error, won't compile
Zweitens start + (end - start) / 2
wird nicht überlaufen, wenn start
und end
sind große positive Zahlen. Bei signierten Operanden ist der Überlauf undefiniert:
int start = 0x7ffffffe, end = 0x7fffffff;
int mid = start + (end - start) / 2; // works as expected
int mid = (start + end) / 2; // overflow... undefined
(Beachten Sie, dass dies end - start
überlaufen kann, aber nur, wenn start < 0
oder end < 0
.)
Oder mit vorzeichenloser Arithmetik wird ein Überlauf definiert, der Ihnen jedoch die falsche Antwort gibt. Bei vorzeichenlosen Operanden start + (end - start) / 2
wird jedoch niemals überlaufen, solange end >= start
.
unsigned start = 0xfffffffeu, end = 0xffffffffu;
unsigned mid = start + (end - start) / 2; // works as expected
unsigned mid = (start + end) / 2; // mid = 0x7ffffffe
Schließlich möchten Sie häufig auf das start
Element runden .
int start = -3, end = 0;
int mid = start + (end - start) / 2; // -2, closer to start
int mid = (start + end) / 2; // -1, surprise!
Fußnoten
1 Nach dem C-Standard ist ptrdiff_t
das Verhalten undefiniert , wenn das Ergebnis der Zeigersubtraktion nicht als a dargestellt werden kann. In der Praxis erfordert dies jedoch die Zuweisung eines char
Arrays unter Verwendung mindestens der Hälfte des gesamten Adressraums.
(start + end)
könnte überlaufen,(end - start)
kann aber nicht.