Topic: Evaluating '&*p' (was: Rebinding references)


Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/11/09
Raw View
Roger Onslow wrote:
 >
 > I missed the original post but...
 >
 > Lets think about it...
 >
 > lets assume (for the sake of argument) we have...
 >
 >     int x;
 >     int* p = &x;
 >     int* q = &*p;
 >
 > 'p' is some bytes which hold the address of the object x
 >
 > '*p' _IS_ the object x - it is those physical bytes of memory where x is and
 > that were pointed to by p
 >
 > '&*p' is therefore EXACTLY the same as &x and gives you the same value as p
 > had originally (ie. the address of x).  It is, literally, the address of the
 > object pointed to by p
 >
 > What is the problem here ??
 >
 > Of course, the value would, officially, be undefined if p was null, because
 > *p is then undefined.  But saying '&*p' is not ok is like saying x/y is
 > invalid because it is undefined when y is 0.

The whole problem *is* the question if it is defined if p is null.
And there the argument is IMHO the same as for x*y/y: If y is 0,
this is undefined, although the division by y and the multiplication
with y cancel out.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Roger Onslow" <No_Spam@hotmail.com>
Date: 1997/10/30
Raw View
I missed the original post but...

Lets think about it...

lets assume (for the sake of argument) we have...

    int x;
    int* p = &x;
    int* q = &*p;

'p' is some bytes which hold the address of the object x

'*p' _IS_ the object x - it is those physical bytes of memory where x is and
that were pointed to by p

'&*p' is therefore EXACTLY the same as &x and gives you the same value as p
had originally (ie. the address of x).  It is, literally, the address of the
object pointed to by p

What is the problem here ??

Of course, the value would, officially, be undefined if p was null, because
*p is then undefined.  But saying '&*p' is not ok is like saying x/y is
invalid because it is undefined when y is 0.

Roger
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/30
Raw View
In comp.std.c++ David R Tribble <david.tribble@central.beasys.com> wrote:

: stephen.clamage_nospam@eng.sun.com (Steve Clamage) responded:

: > David R Tribble wrote:

: > > ... The unary '*' and '&'
: > > operators are, in fact, inverses of each other.  When placed together,
: > > they cancel out semantically.
: >
: > That assertion is not borne out by any language in the standard that I
: > can find.

: Well, it may not be written in the standard, but it's a property of the
: operators that can be deduced from their definitions.

Only when * is applied to a pointer value that is suitable for
dereferencing or (and this depends on your notion of inverse) a
pointer value that is undefined, e.g., a pointer to a deallocated
object.

If we read unary * as "the object at", then when p == 0, *p represents
"the object at 0", which is an undefined notion.  To speak of "the
address of the object at 0" would seem to be equally undefined.  In
general, the use of the definite article, as in "the ...", presupposes
that there is a ...  and that there is only one of them.  If there
isn't a ..., then "the ..."  is an undefined notion, whose properties
(e.g., its address) are equally undefined.

Tom Payne
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: stephen.clamage_nospam@eng.sun.com (Steve Clamage)
Date: 1997/10/28
Raw View
On 24 Oct 97 18:54:52 GMT, David R Tribble
<david.tribble@central.beasys.com> wrote:

>...  Evaluating '&*p' does not require reading '*p'.
>
>It all has to do with understanding the semantics of the '&' operator; the
>operation of the '*' operator is immaterial.  The definition of the '&'
>operator is (quoting from the ANSI/ISO C doc):
>
>  6.3.3.2  Address and indirection operators
>  ...
>  The result of the unary '&' (address-of) operator is a pointer to the
>  object or function designated by its operand.  If the operand has type
>  "type", the result has type "pointer to type".
>  ...

Please note the words "pointer to the object or function designated by
its operand." If p is for example a null pointer, then *p by
definition does not designate any object or function. The result of
applying the '&' operator to *p is undefined, because the result of *p
is undefined.

Notice the subject of whether the value of *p needs to be "read" does
not arise. Note also that a non-volatile value does not always "need
to be read" when it appears in an expressions, because sometimes the
compiler can deduce its value without reading it. Potential compiler
optimizations do not affect (and are not allowed to affect) the
validity of source code.

>... The unary '*' and '&'
>operators are, in fact, inverses of each other.  When placed together,
>they cancel out semantically.

That assertion is not borne out by any language in the standard that I
can find. Contrariwise, when *p is invalid, &*p is also invalid, as I
noted above.

---
Steve Clamage, stephen.clamage_nospam@eng.sun.com
( Note: remove "_nospam" when replying )
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/29
Raw View
I, David R Tribble <david.tribble@central.beasys.com>, wrote:
> > ...  Evaluating '&*p' does not require reading '*p'.
> >
> > It all has to do with understanding the semantics of the '&' operator; the
> > operation of the '*' operator is immaterial.  The definition of the '&'
> > operator is (quoting from the ANSI/ISO C doc):
> >
> >   6.3.3.2  Address and indirection operators
> >   ...
> >   The result of the unary '&' (address-of) operator is a pointer to the
> >   object or function designated by its operand.  If the operand has type
> >   "type", the result has type "pointer to type".
> >   ...

stephen.clamage_nospam@eng.sun.com (Steve Clamage) responded:
> Please note the words "pointer to the object or function designated by
> its operand." If p is for example a null pointer, then *p by
> definition does not designate any object or function. The result of
> applying the '&' operator to *p is undefined, because the result of *p
> is undefined.

Yes, undefined.  Which means my little diatribe does not apply to the
semantic evaluations.  It also means that a conforming implementation can,
if it wanted to, check that '*p' is a valid object (or at least that 'p' is
not null) before applying the '&' operator to it and generate a runtime
exception if it's not.  Just like some implementations generate an
exception (usually called a "segmentation violation") when evaluating
'*p' when 'p' is invalid.  (But I've never come across a compiler that
bothered to check for an invalid operand of '&'.)

> Notice the subject of whether the value of *p needs to be "read" does
> not arise. Note also that a non-volatile value does not always "need
> to be read" when it appears in an expressions, because sometimes the
> compiler can deduce its value without reading it. Potential compiler
> optimizations do not affect (and are not allowed to affect) the
> validity of source code.

True.

> > ... The unary '*' and '&'
> > operators are, in fact, inverses of each other.  When placed together,
> > they cancel out semantically.
>
> That assertion is not borne out by any language in the standard that I
> can find.

Well, it may not be written in the standard, but it's a property of the
operators that can be deduced from their definitions.  Just as the bitwise
unary '~' operator is its own inverse, but this fact is not mentioned in
the standard either.

> Contrariwise, when *p is invalid, &*p is also invalid, as I
> noted above.

Of course you are correct.  As I admitted, in cases of undefined behavior,
all bets are off with regard to "proper" semantic meanings.  I sit
corrected.

-- David R. Tribble, david.tribble@central.beasys.com --
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1997/10/28
Raw View
David R Tribble <david.tribble@central.beasys.com> writes:

|>  kanze@gabi-soft.fr (J. Kanze)
|>  > Tom Payne <thp@cs.ucr.edu> writes:
|>  > |>  Note that sizeof(*p) differs from &(*p) in that the latter, in
|>  > |>  general, requires reading p, while (as long as p is not an array)
|>  > |>  sizeof(*p) can be determined at compile time.
|>  >
|>  > From a standards point of view, sizeof(*p) differs from &(*p) in that in
|>  > the first, the (sub-)expression *p is not evaluated, whereas in the
|>  > second, it is.
|>
|>  No, it's not.  Evaluating '&*p' does not require reading '*p'.

So what?  The expression "*p = 0" doesn't require reading p either, but
it is undefined behavior.  Evaluating *p is what results in the
undefined behavior, and the standard requires *p to be evaluated in the
expression "&*p".

|>  It all has to do with understanding the semantics of the '&' operator; the
|>  operation of the '*' operator is immaterial.  The definition of the '&'
|>  operator is (quoting from the ANSI/ISO C doc):
|>
|>    6.3.3.2  Address and indirection operators
|>    ...
|>    The result of the unary '&' (address-of) operator is a pointer to the
|>    object or function designated by its operand.  If the operand has type
|>    "type", the result has type "pointer to type".
|>    ...
|>
|>  Nowhere does it mention that the operand of '&' is evaluated, accessed, or
|>  otherwise affected in any way.  The semantics of the '&' operator differs
|>  from all other operators, in that it evaluates a *property* of its operand
|>  (i.e., the operand's address) rather than its *value*.

Where do you get this.  In the standard, expressions are "evaluated",
the case of an operand to sizeof is an explicit exception (and I think,
off hand, the only exception).  I don't see where the requirements of
the '&' operator are fundamentally different from those of the left
argument of the '=' operator -- in both cases, the standard requires an
lvalue.  This has nothing to do with whether the expression is evaluated
or not.

|>  In evaluating '&x' the operand 'x' is not accessed in any way other than
|>  what is required to determine its address in memory.  (On real CPUs, this
|>  is simply an address computation and the value of 'x' is never fetched.)

Note that you can say exactly the same thing for the left argument of
assignment -- what is required (by the implementation) is its address.
And I've yet to see a compiler which fetched the left argument of
assignment.  (In this particular case, I believe that it is illegal --
you can assign to an uninitialized variable.)

|>  This is true for '&*p' as well; the expression evaluates to the address
|>  of '*p', which is 'p'.  There is no dereferencing of 'p' involved in
|>  determining the value of 'p', in spite of the fact that unary '*' is
|>  applied to 'p', because of the semantics of '&'.  The unary '*' and '&'
|>  operators are, in fact, inverses of each other.  When placed together,
|>  they cancel out semantically.

So what?  Consider a similar example: "sqrt( x ) * sqrt( x )".  The
operations cancel each other out, but if x is negative, the program is
still illegal.

The standard says that the expression will be evaluated (or rather, it
doesn't say that it won't be evaluated).  Evaluating *p where p does not
point to a valid object results in undefined behavior.  The fact that
most compilers do not actually access the object in certain
circumstances is irrelevant with regards to the standard.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
        I'm looking for a job -- Je recherche du travail
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/24
Raw View
kanze@gabi-soft.fr (J. Kanze)
> Tom Payne <thp@cs.ucr.edu> writes:
> |>  Note that sizeof(*p) differs from &(*p) in that the latter, in
> |>  general, requires reading p, while (as long as p is not an array)
> |>  sizeof(*p) can be determined at compile time.
>
> From a standards point of view, sizeof(*p) differs from &(*p) in that in
> the first, the (sub-)expression *p is not evaluated, whereas in the
> second, it is.

No, it's not.  Evaluating '&*p' does not require reading '*p'.

It all has to do with understanding the semantics of the '&' operator; the
operation of the '*' operator is immaterial.  The definition of the '&'
operator is (quoting from the ANSI/ISO C doc):

  6.3.3.2  Address and indirection operators
  ...
  The result of the unary '&' (address-of) operator is a pointer to the
  object or function designated by its operand.  If the operand has type
  "type", the result has type "pointer to type".
  ...

Nowhere does it mention that the operand of '&' is evaluated, accessed, or
otherwise affected in any way.  The semantics of the '&' operator differs
from all other operators, in that it evaluates a *property* of its operand
(i.e., the operand's address) rather than its *value*.

In evaluating '&x' the operand 'x' is not accessed in any way other than
what is required to determine its address in memory.  (On real CPUs, this
is simply an address computation and the value of 'x' is never fetched.)
This is true for '&*p' as well; the expression evaluates to the address
of '*p', which is 'p'.  There is no dereferencing of 'p' involved in
determining the value of 'p', in spite of the fact that unary '*' is
applied to 'p', because of the semantics of '&'.  The unary '*' and '&'
operators are, in fact, inverses of each other.  When placed together,
they cancel out semantically.

Unfortunately, the exact semantics of '&*p' are not defined by ANSI
(even though '*&p' is defined to mean 'p').  I think that it might have
been the subject of a Clarification Request to the C committee, though.

-- David R. Tribble, david.tribble@beasys.com --
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Tom Payne <thp@cs.ucr.edu>
Date: 1997/10/26
Raw View
In comp.std.c++ David R Tribble <david.tribble@central.beasys.com> wrote:
: kanze@gabi-soft.fr (J. Kanze)
: > Tom Payne <thp@cs.ucr.edu> writes:
: > |>  Note that sizeof(*p) differs from &(*p) in that the latter, in
: > |>  general, requires reading p, while (as long as p is not an array)
: > |>  sizeof(*p) can be determined at compile time.
: >
: > From a standards point of view, sizeof(*p) differs from &(*p) in that in
: > the first, the (sub-)expression *p is not evaluated, whereas in the
: > second, it is.

: No, it's not.  Evaluating '&*p' does not require reading '*p'.

: It all has to do with understanding the semantics of the '&' operator; the
: operation of the '*' operator is immaterial.  The definition of the '&'
: operator is (quoting from the ANSI/ISO C doc):

:   6.3.3.2  Address and indirection operators
:   ...
:   The result of the unary '&' (address-of) operator is a pointer to the
:   object or function designated by its operand.  If the operand has type
:   "type", the result has type "pointer to type".
:   ...

: Nowhere does it mention that the operand of '&' is evaluated, accessed, or
: otherwise affected in any way.  The semantics of the '&' operator differs
: from all other operators, in that it evaluates a *property* of its operand
: (i.e., the operand's address) rather than its *value*.

You are correct that the & operator takes an lvalue, e.g., *0, as its
argument (i.e., an expression that designates an object).  Whenever an
lvalue occurs as a subexpression of an evaluated expression it is
generally evaluated -- exections would be when it appears as an
argument of sizeof and when it is in a short-circuited branch of say
&&, etc.  Note that evaluation of an lvalue generally involves
computation of an address but not accessing the object at that
address.  In contexts where the lvalue is converted to an rvalue,
however, the designated object is (almost) always read.

: In evaluating '&x' the operand 'x' is not accessed in any way other than
: what is required to determine its address in memory.

Right, there is no need to access it.

: (On real CPUs, this
: is simply an address computation and the value of 'x' is never fetched.)

Right.

: This is true for '&*p' as well; the expression evaluates to the address
: of '*p', which is 'p'.

Or rather the content of p.

: There is no dereferencing of 'p' involved in
: determining the value of 'p', in spite of the fact that unary '*' is
: applied to 'p', because of the semantics of '&'.

One must distinguish between "dereferencing p" (i.e., evaluating *p)
and "fetching *p", which is not done unless *p is converted to an
rvalue.  For instance, in executing *p=0 we dereference p, but we do
not fetch *p.

: The unary '*' and '&'
: operators are, in fact, inverses of each other.  When placed together,
: they cancel out semantically.

: Unfortunately, the exact semantics of '&*p' are not defined by ANSI
: (even though '*&p' is defined to mean 'p').  I think that it might have
: been the subject of a Clarification Request to the C committee, though.


It shoud be as straightforward as deciding "Who's buried in Grant's
tomb?"  Unfortunately, in some cases the architecture tail wags the
language dog.  Remember that some architectures trap some read
accesses to pointer registers holding invalid values.  When p dangles,
evaluating &*p might invoke a trap handler rather than simply
returning the content of p.  The standards have made concession
to these.

Tom Payne
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]