Il y a trois raisons.
Tout d'abord, start + (end - start) / 2
fonctionne même si vous utilisez des pointeurs, à condition qu'il end - start
ne déborde pas de 1 .
int *start = ..., *end = ...;
int *mid = start + (end - start) / 2; // works as expected
int *mid = (start + end) / 2; // type error, won't compile
Deuxièmement, start + (end - start) / 2
ne débordera pas si start
et end
sont de grands nombres positifs. Avec les opérandes signés, le débordement n'est pas défini:
int start = 0x7ffffffe, end = 0x7fffffff;
int mid = start + (end - start) / 2; // works as expected
int mid = (start + end) / 2; // overflow... undefined
(Notez que cela end - start
peut déborder, mais seulement si start < 0
ou end < 0
.)
Ou avec l'arithmétique non signée, le débordement est défini mais vous donne la mauvaise réponse. Cependant, pour les opérandes non signés, start + (end - start) / 2
ne débordera jamais tant que end >= start
.
unsigned start = 0xfffffffeu, end = 0xffffffffu;
unsigned mid = start + (end - start) / 2; // works as expected
unsigned mid = (start + end) / 2; // mid = 0x7ffffffe
Enfin, vous souhaitez souvent arrondir vers l' start
élément.
int start = -3, end = 0;
int mid = start + (end - start) / 2; // -2, closer to start
int mid = (start + end) / 2; // -1, surprise!
Notes de bas de page
1 Selon la norme C, si le résultat de la soustraction du pointeur n'est pas représentable comme a ptrdiff_t
, alors le comportement est indéfini. Cependant, en pratique, cela nécessite d'allouer un char
tableau utilisant au moins la moitié de l'espace d'adressage entier.
(start + end)
pourrait déborder, alors que(end - start)
ne le peut pas.