Adding two pointers

Chris Torek chris at mimsy.UUCP
Sat May 6 20:07:10 AEST 1989


In article <922 at garcon.cso.uiuc.edu> mcdaniel at uicsrd.csrd.uiuc.edu
(Tim McDaniel) writes:
>One question has not yet been answered, and it makes this whole fiasco
>moot.

Indeed, it is the heart of the matter.  (But beware the word `moot',
for it means both `not worthy of discussion' and `worthy of discussion'.
A `moot' is a meeting, where a group discusses some topic of interest.
The discussion is often interminable and leads to no resolution; hence
the double meaning.)

>What additional power does pointer addition give?  What can be
>done with it that can't be done about as easily as with pointer
>subtraction?

Presumably the reason someone might want to write

	some_type base[N], *low, *high, *mid;
	...
	mid = (low + high) / 2;

is to avoid the scaling that occurs with

	mid = ((low - base) + (high - base)) / 2 + base;

which, if compiled in the most straightforward (and stupid) manner,
yeilds machine code much like this:

	// pretend everything is an int
	// mid <- ( (low-base)/size + (high-base)/size ) * size + base
	sub	base,low,r0
*1	div	r0,size,r0	# `size' being a constant
	sub	base,high,r1
*2	div	r1,size,r1
	add	r0,r1,r0
	div	r0,$2,r0	# divide by 2 is really shift right 1
*3	mul	r0,size,r0
	add	r0,base,mid

The three lines marked with `*' are unnecessary.  They cannot be
deleted if the code is expressed as in the second comment above,
because it is not clear that the division by `size' (*1 and *2) does
not discard low bits---for instance, if size is 2, that it does not
force the result of the subtractions to be even.  We, however, know
that both `low' and `high' point into the same array, and that the
result of the two `sub's just before the starred `div's are in fact
a multiple of `size', that no bits are discarded, and that the marked
`div' and `mul' instructions can in fact be factored out.

But subtraction of pointers is a common occurrence in C, and any
optimising compiler worth its name should note this.  Subtraction of
two pointers is only defined if both point to elements of the same
array; and when they do, it is guaranteed that the difference is a
whole number of elements, or in other words a proper multiple of `size'.
So the compiler should reduce this to

	sub	base,low,r0
	sub	base,high,r1
	add	r0,r1,r0
	div	r0,$2,r0
	add	r0,base,mid

which is what we need anyway (to avoid overflow).

(Sad to say, gcc does not win this one....  It does, however, avoid
divides by using sub+bge+add+label+shift.  The bge+add+label sequence
is unnecessary.  Is rms listening?)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at mimsy.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list