[comp.lang.c] p[1] vs. *

chip@tct.uucp (Chip Salzenberg) (08/28/90)

According to cbp@icc.com (Chris Preston):
>  For instance, I am told that the following is a problem in Kanji
>
>  char p[10]; /* xscc provides for allowing twenty bytes as needed in Kanji */
>
>  *(p+1)='x'; /* this is the next byte, and an error */ 
>   p[n+1]='x'; /* this is the next _character_ and ok */

Just so no one panics: Unless I misunderstand Chris Preston's example,
this bit of code is not a harbinger of things to come, but rather an
artifact of a broken compiler.

Any compiler that considers "*(p+1)" and "p[1]" to be different does
not comply with the ANSI standard -- or with K&R, for that matter.
Since time immemorial, "*(a+b)" and "a[b]" have been synonymous, and
such is C today.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>

prs@io.UUCP (Paul Schmidt) (08/30/90)

In article <26D952F5.4E44@tct.uucp> chip@tct.uucp (Chip Salzenberg) writes:
>
>Any compiler that considers "*(p+1)" and "p[1]" to be different does
>not comply with the ANSI standard -- or with K&R, for that matter.


So, that means that the compiler must know the size of the elements of
array p, and that *(p+1) does not add 1 to p, but instead adds
sizeof(array_element_type) to p?

I must confess that I use p[1] in these cases, and count on the compiler
to optimize for me.

henry@zoo.toronto.edu (Henry Spencer) (08/31/90)

In article <1745@io.UUCP> prs@eng.ileaf.com (Paul Schmidt) writes:
>>Any compiler that considers "*(p+1)" and "p[1]" to be different does
>>not comply with the ANSI standard -- or with K&R, for that matter.
>
>So, that means that the compiler must know the size of the elements of
>array p, and that *(p+1) does not add 1 to p, but instead adds
>sizeof(array_element_type) to p?

Although you phrased it a bit poorly, that is correct.  What is the
*meaning* of adding 1 to a pointer?  In C, it means that the pointer
is increased as far as necessary to point to the next array element.
What happens to the actual bit patterns is the compiler's business;
typically this will, indeed, involve adding sizeof(*p) to p, considered
as an integer.

>I must confess that I use p[1] in these cases, and count on the compiler
>to optimize for me.

Ignoring some syntactic nit-picking, p[1] is *identical* to *(p+1), by
definition of the C subscripting operation.
-- 
TCP/IP: handling tomorrow's loads today| Henry Spencer at U of Toronto Zoology
OSI: handling yesterday's loads someday|  henry@zoo.toronto.edu   utzoo!henry

bruce@seismo.gps.caltech.edu (Bruce Worden) (09/01/90)

In article <1745@io.UUCP> prs@eng.ileaf.com (Paul Schmidt) writes:

> [ material deleted ]
>So, that means that the compiler must know the size of the elements of
>array p, and that *(p+1) does not add 1 to p, but instead adds
>sizeof(array_element_type) to p?

Yes.  It is very important to understand that point if you are going to be
shuffling pointers around.

>I must confess that I use p[1] in these cases, and count on the compiler
>to optimize for me.

In a simple case like p[1] the compiler may well optimize, but then it isn't 
a particularly time consuming operation.  Though we are getting bit off of the 
original subject, in the case of a loop, the performance difference between 
   *p1++ = *a1++ * *b1++;  
and 
    p2[i] = a2[i] * b2[i]; 
can be significant.  The performance strongly depends on the compiler and, 
in the case of floating-point operands, how well the compiler exploits the 
features available in the hardware.
--------------------------------------------------------------------------
C. Bruce Worden                            bruce@seismo.gps.caltech.edu
252-21 Seismological Laboratory, Caltech, Pasadena, CA 91125

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/01/90)

In article <1990Aug31.190103.15043@laguna.ccsf.caltech.edu> bruce@seismo.gps.caltech.edu (Bruce Worden) writes:
> In article <1745@io.UUCP> prs@eng.ileaf.com (Paul Schmidt) writes:
> >I must confess that I use p[1] in these cases, and count on the compiler
> >to optimize for me.
> In a simple case like p[1] the compiler may well optimize, but then it isn't 
> a particularly time consuming operation.

Huh? p[1] means exactly the same thing as *(p+1). At least two compilers
here (neither pcc-based) do that translation as the very first step.
There's no ``optimization'' involved.

>    *p1++ = *a1++ * *b1++;  
>     p2[i] = a2[i] * b2[i]; 

Note that on vector machines the latter is much faster in a loop.

---Dan

bruce@seismo.gps.caltech.edu (Bruce Worden) (09/01/90)

In article <29605:Aug3120:51:0290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:

>Huh? p[1] means exactly the same thing as *(p+1). At least two compilers
>here (neither pcc-based) do that translation as the very first step.
>There's no ``optimization'' involved.

It is really an extremely small point.  As far as I know, nothing specifies 
that the code generated by the two statements has to be identical, only that 
the results are the same.  One could imagine a compiler that did one less
efficiently than the other.

>>    *p1++ = *a1++ * *b1++;  
>>     p2[i] = a2[i] * b2[i]; 
>Note that on vector machines the latter is much faster in a loop.

My point exactly.  Except that the example you give isn't necessarily
true.  On our Convex both will vectorize, and the run time is the same.
--------------------------------------------------------------------------
C. Bruce Worden                            bruce@seismo.gps.caltech.edu
252-21 Seismological Laboratory, Caltech, Pasadena, CA 91125

throopw@sheol.UUCP (Wayne Throop) (09/02/90)

> From: bruce@seismo.gps.caltech.edu (Bruce Worden)
>> (Paul Schmidt)
>> *(p+1) does not add 1 to p, but instead adds
>> sizeof(array_element_type) to p?
> Yes.

No.  Or less bluntly, that's not (IMHO) a very good way of putting it. 
Bruce is right as far as he goes, but I think Paul's phrase above is
misleading. 

What I'm objecting to is the dimensionless "adding one to it (a pointer)".
One what? People most probably mean "one byte" by this, but I don't
think peoples' understanding of pointer arithmetic is strong enough to
trust their notions of "add one to" a pointer should be trusted.  And I
think history bears me out. 

Or to be specific, I druther see the above exchange be something like

     Q. *(p+1) does not add 1 to p, 
        but instead adds sizeof(array_element_type) to p?

     A. No.  It produces a pointer value that references the
        next array_element_type array element after the one
        referenced by p.  On byte addressed machines, the bit
        pattern of this pointer, when treated as an integer,
        is often an integer sizeof(array_element_type) greater
        than the integer gotten by treating the bits of p as
        an integer.  But this latter fact is a coincidence produced
        by a particular implementation of C pointers.

Now, I suppose this seems awfully picky.  "Didn't he just say that" and
all that.  But the point is that the underlying assumption of a smooth
byte-granular address space with pointers represented as integer offsets
into this address space is NOT the best way of explaining pointers, even
if it is the one so many people use.

Or to try putting it another way, I think it is misleading to say that
"adding one to p 'really' adds sizeof(*p) to p".  I disagree.  I say it
"really" adds 1, and the result points at an element in the array into
which p points which is offset exactly 1 array element from where p
points.
--
Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org

steve@groucho.ucar.edu (Steve Emmerson) (09/03/90)

In <0901@sheol.UUCP> throopw@sheol.UUCP (Wayne Throop) writes:

>Or to try putting it another way, I think it is misleading to say that
>"adding one to p 'really' adds sizeof(*p) to p".  I disagree.  I say it
>"really" adds 1, and the result points at an element in the array into
>which p points which is offset exactly 1 array element from where p
>points.

Isn't the point moot if a conforming program can't tell the difference?

Steve Emmerson        steve@unidata.ucar.edu        ...!ncar!unidata!steve

throopw@sheol.UUCP (Wayne Throop) (09/03/90)

> From: steve@groucho.ucar.edu (Steve Emmerson) 
>> [...] it is misleading to say that "adding one to p 'really' adds
>> sizeof(*p) to p".  [...] it "really" adds 1, and the result points at an
>> element [...] which is offset exactly 1 array element [...]
> Isn't the point moot if a conforming program can't tell the difference?

In terms of correctness, I agree (once one fills in the implied
information that one is assuming integer arithmetic on byte offset
pointers). 

But my point wasn't directed at correctness, but at communication.  So
I'd say the point is moot only if the difference in phrasing doesn't
mislead programmers into producing nonconforming programs.  And I think
it pretty clear that this particular issue misleads more people than
many another, and that extreme care in communication is warranted. 

Then again, maybe I'm just too picky... but I still don't think so.
--
Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org

hunter@Oswego.EDU (Eric Hunter) (09/04/90)

In <0901@sheol.UUCP> throopw@sheol.UUCP (Wayne Throop) writes:

>Or to try putting it another way, I think it is misleading to say that
>"adding one to p 'really' adds sizeof(*p) to p".  I disagree.  I say it
>"really" adds 1, and the result points at an element in the array into
>which p points which is offset exactly 1 array element from where p points.

It doesn't "really" add 1; it increments the pointer variable to the next
available address.

Eric.
-------------------------------------------------------------------------------
| Eric Hunter              | The difference between emacs, and vi, is like the| 
| hunter@oswego.oswego.edu | difference between making love, and masturbation.| 
-------------------------------------------------------------------------------

martin@mwtech.UUCP (Martin Weitzel) (09/04/90)

In article <1990Aug31.163647.11121@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <1745@io.UUCP> prs@eng.ileaf.com (Paul Schmidt) writes:
[...]
>>So, that means that the compiler must know the size of the elements of
>>array p, and that *(p+1) does not add 1 to p, but instead adds
>>sizeof(array_element_type) to p?
[...]
>Ignoring some syntactic nit-picking, p[1] is *identical* to *(p+1), by
>definition of the C subscripting operation.

And in all flavours of UNIX I've ever used there is a compiler option
(usually -S) which leaves an assembly language file (usually suffixed .s) 
and I've never seen a difference in the assembly source for both
constructs

But note: The fact that *(p+1) can be interchanged with p[1] (and even
with 1[p]) does of course NOT mean that there is no difference between
pointers and arrays. With: T a[10], *ap = a; the machine code produced
for a[1] is DIFFERENT from the code for *(ap+1); but the latter is
the same as for ap[1] and the former is the same as for *(a+1). 
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

mat@mole-end.UUCP (Mark A Terribile) (09/04/90)

In article <1745@io.UUCP>, prs@io.UUCP (Paul Schmidt) writes:
> In article <26D952F5.4E44@tct.uucp> chip@tct.uucp (Chip Salzenberg) writes:
> >
> >Any compiler that considers "*(p+1)" and "p[1]" to be different does
> >not comply with the ANSI standard -- or with K&R, for that matter.
 
 
> So, that means that the compiler must know the size of the elements of
> array p, and that *(p+1) does not add 1 to p, but instead adds
> sizeof(array_element_type) to p?

What's the problem?  The compiler needs to know the length anyway.  And yes,
the pointer is adjusted by the length of the object at which it (is presumed
to) point.
 
> I must confess that I use p[1] in these cases, and count on the compiler
> to optimize for me.

What does optimization have to do with anything?  The compiler can generate
the same code for both expressions.  Because C gives the programmer so much
addressing control and because aliasing can occur, the compiler cannot
always do strength reductions.

The equivalence of  p[ i ]  and  *( p + i )  is at the very heart of the C
language definition.  If you are programming in C, you CAN rely upon it,
not by some coincidence or compiler peculiarity, but in the most portable
way of all, by the actual definition of the language.  If the compiler
writer cannot implement this behavior well, he cannot implement C well on
that machine.
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile

throopw@sheol.UUCP (Wayne Throop) (09/10/90)

>> throopw@sheol.UUCP
>>I think it is misleading to say that "adding one to p 'really' adds
>>sizeof(*p) to p". [...]  I say it "really" adds 1, and the result [...]
>>points at an element [...] offset exactly 1

> From: hunter@Oswego.EDU (Eric Hunter)
> It doesn't "really" add 1; it increments the pointer variable to the next
> available address.

Which, I still claim, is "really" adding one.  My argument was against
assuming that the integer representation of pointers was to indicate a
byte offset.  This is not true for some current machines, and is at
best a misleading way of thinking about the situation.

"The next available address" may well NOT be "sizeof element" architectural
units away from the address one starts with.  Or it may well be exactly
one unit away, for element type of short, or int, or even double.

I think it is a bad idea to explain abstract things in terms of a concrete
implementation in other than examples.
--
Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org