Hay tres razones
En primer lugar, start + (end - start) / 2
funciona incluso si está utilizando punteros, siempre que end - start
no se desborde 1 .
int *start = ..., *end = ...;
int *mid = start + (end - start) / 2; // works as expected
int *mid = (start + end) / 2; // type error, won't compile
En segundo lugar, start + (end - start) / 2
¿No desbordamiento si start
y end
son grandes números positivos. Con operandos firmados, el desbordamiento no está definido:
int start = 0x7ffffffe, end = 0x7fffffff;
int mid = start + (end - start) / 2; // works as expected
int mid = (start + end) / 2; // overflow... undefined
(Tenga en cuenta que end - start
puede desbordarse, pero solo si start < 0
o end < 0
.)
O con aritmética sin signo, se define el desbordamiento pero le da la respuesta incorrecta. Sin embargo, para operandos sin firmar, start + (end - start) / 2
nunca se desbordará mientras end >= start
.
unsigned start = 0xfffffffeu, end = 0xffffffffu;
unsigned mid = start + (end - start) / 2; // works as expected
unsigned mid = (start + end) / 2; // mid = 0x7ffffffe
Finalmente, a menudo quieres redondear hacia el start
elemento.
int start = -3, end = 0;
int mid = start + (end - start) / 2; // -2, closer to start
int mid = (start + end) / 2; // -1, surprise!
Notas al pie
1 Según el estándar C, si el resultado de la resta del puntero no es representable como a ptrdiff_t
, entonces el comportamiento es indefinido. Sin embargo, en la práctica, esto requiere asignar una char
matriz utilizando al menos la mitad del espacio de direcciones completo.
(start + end)
puede desbordarse, mientras(end - start)
que no puede.