Topic: reinterpret_cast<char *>( &pod ) -- does this always work?


Author: vm@nowhere.invalid ("Vladim r Marko")
Date: Wed, 2 Jun 2004 17:44:00 +0000 (UTC)
Raw View
X-No-Acknowledgement
X-No-Reject-Notice
"John Potter" <jpotter@falcon.lhup.edu> wrote in message
news:La5vc.34059$zO3.4232@newsread2.news.atl.earthlink.net...
> On Tue, 1 Jun 2004 17:06:34 +0000 (UTC), Michiel.Salters@logicacmg.com
> (Michiel Salters) wrote:
>
> > alan_mckenney1@yahoo.com (Alan McKenney) wrote in message
news:<16a885f9.0405270933.1e05001e@posting.google.com>...
>
> > > In some C++ groups, people recommend outputing
> > > random data by doing something like:
>
> > >      POD_type my_data;
> > >      ....
> > >      char *ptr = reinterpret_cast<char *>( &my_data );
>
> > > This generally works on the more popular architectures,
> > > such as SPARC, Intel, etc., but is it *required* to work?
>
> > Yes, for char* and unsigned char*. PODs may be read via expressions
> > of char type (3.10/15), and the meaning of the cast is given by
> > 5.2.10/10. The pointer must refer to the same object.
>
> Wrong reference.  5.2.10/10 is about reference casts which are not used
> here.
>
>    char& ref(reinterpret_cast<char&>(my_data);
>
> Since 5.2.10/7 states that the above pointer cast is well formed, the
> reference cast would also be well formed and then by 5.2.10/10 says
> that it refers to the same object.
>
> Note that 5.2.10/10 does not say that the well formed pointer cast will
> produce a pointer to the same object.  It would be valid for the
> implementation to flip all bits on all pointer reinterpret_casts.

This would break the requirement on null pointer reinterpret_cast
(from now on simply r_cast) unless the implementation provided
two values of null pointer that compared equal. A better example
is an implementation that flips all bits iff odd number of bits are set
(given that the pointer has odd number of bits and null pointer
has all bits cleared). I would point out that such an implementation
is standard conforming even though the r_casts
  r_cast<T1*>(r_cast<T2*>(r_cast<T3*>(p)))
do not yield the original value. The standard could require
(but it does not require) that such conversion yields the original
value if the alignment requirements on T2 and T3 are not stricter
than those of T1. Or, perhaps, that the mapping performed by
r_cast be transitive, i.e.
  r_cast<T2*>(r_cast<T1*>(p)) == r_cast<T2*>(p) .
Even then one can make up a standard conforming r_cast
implementation which makes the new pointer unusable.
For example, each type T will have a number r_cast_id(T)
and the cast from T1* to T2* rotates the bits of the casted
pointer value r_cast_id(T1) times to the left and
r_cast_id(T2) times to the right. Whenever
  (r_cast_id(T1)-r_cast_id(T2))%number_of_bits !=0,
things get weird.

> Casting from one type to another and back to the original type would
> then work properly and the above cast would not do anything useful.
>
> QoI says it will work as expected.  If paranoid,
>
>    char* ptr = &reinterpret_cast<char&>( my_data );
>
> uses 5.2.10/10 and must work.
>
> John

Well, if paranoid, try some union workaround. To explain
why I'll split 5.2.10/10 to sentences and try to interpret
each one in order of appearance.

(s1) An lvalue expression of type T1 can be cast to the type
``reference to T2'' if an expression of type ``pointer to T1''
can be explicitly converted to the type ``pointer to T2'' using
a reinterpret_cast.

This says which r_casts of references are valid.

(s2) That is, a reference cast reinterpret_cast<T&>(x) has
the same effect as the conversion *reinterpret_cast<T*>(&x)
with the built-in & and * operators.

This sentence starts with "that is," which makes it look like
an explanation of (s1). However, the rest of the sentence
is clearly not an explanation of (s1), it's rather the full
definition of r_cast behaviour.

(s3) The result is an lvalue that refers to the same object as
the source lvalue, but with a different type.

Given that we already have the definition of r_cast's
behaviour, this must be the definition of the phrase
"to point to the same object, but with a different type".

(s4) No temporary is created, no copy is made, and
constructors (class.ctor) or conversion functions (class.conv)
are not called.

This is clear and needs no explanation.

Summary: The r_cast of a pointer need not point to the same
    memory location, it is implementation defined. The r_cast
    of a reference is defined by means of r_cast of a pointer
    and thus the result may be a reference to a different
    memory location as well.

If you disagree, please reply (to the group). I would
really like to know if there is something wrong with my
interpretation.

On the other hand, if this seems to be a valid interpretation,
the WG21 should remove "that is" from (s2) and make
(s3) more clear.

Regards

Vladimir Marko





---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: vm@nowhere.invalid ("Vladim r Marko")
Date: Thu, 3 Jun 2004 17:27:44 +0000 (UTC)
Raw View
X-No-Acknowledgement
X-No-Reject-Notice
""Vladim   r Marko"" <vm@nowhere.invalid> wrote in message
news:c9k19j$9ur$1@news.wplus.net...
> X-No-Acknowledgement
> X-No-Reject-Notice
> "John Potter" <jpotter@falcon.lhup.edu> wrote in message
> news:La5vc.34059$zO3.4232@newsread2.news.atl.earthlink.net...
> > On Tue, 1 Jun 2004 17:06:34 +0000 (UTC), Michiel.Salters@logicacmg.com
> > (Michiel Salters) wrote:
> >
> > > alan_mckenney1@yahoo.com (Alan McKenney) wrote in message
> news:<16a885f9.0405270933.1e05001e@posting.google.com>...
> >
[snip]
> This would break the requirement on null pointer reinterpret_cast
> (from now on simply r_cast) unless the implementation provided
> two values of null pointer that compared equal. A better example
> is an implementation that flips all bits iff odd number of bits are set
> (given that the pointer has odd number of bits and null pointer
> has all bits cleared).
[snip]

given that the pointer has _even_ number of bits...

Sorry for that mistake.

Vladimir Marko



---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: falk.tannhauser@crf.canon.fr (Falk =?iso-8859-1?Q?Tannh=E4user?=)
Date: Thu, 3 Jun 2004 17:28:34 +0000 (UTC)
Raw View
"Vladim=EDr Marko" wrote:
>=20
> "John Potter" <jpotter@falcon.lhup.edu> wrote in message
> news:La5vc.34059$zO3.4232@newsread2.news.atl.earthlink.net...
> >
> > Wrong reference.  5.2.10/10 is about reference casts which are not us=
ed
> > here.
> >
> >    char& ref(reinterpret_cast<char&>(my_data);
> >
> > Since 5.2.10/7 states that the above pointer cast is well formed, the
> > reference cast would also be well formed and then by 5.2.10/10 says
> > that it refers to the same object.
> >
> > Note that 5.2.10/10 does not say that the well formed pointer cast wi=
ll
> > produce a pointer to the same object.  It would be valid for the
> > implementation to flip all bits on all pointer reinterpret_casts.
>=20
> This would break the requirement on null pointer reinterpret_cast
> (from now on simply r_cast) unless the implementation provided
> two values of null pointer that compared equal. A better example
> is an implementation that flips all bits iff odd number of bits are set
> (given that the pointer has odd number of bits and null pointer
> has all bits cleared). I would point out that such an implementation
> is standard conforming even though the r_casts
>   r_cast<T1*>(r_cast<T2*>(r_cast<T3*>(p)))
> do not yield the original value. The standard could require
> (but it does not require) that such conversion yields the original
> value if the alignment requirements on T2 and T3 are not stricter
> than those of T1. Or, perhaps, that the mapping performed by
> r_cast be transitive, i.e.
>   r_cast<T2*>(r_cast<T1*>(p)) =3D=3D r_cast<T2*>(p) .
> Even then one can make up a standard conforming r_cast
> implementation which makes the new pointer unusable.
> For example, each type T will have a number r_cast_id(T)
> and the cast from T1* to T2* rotates the bits of the casted
> pointer value r_cast_id(T1) times to the left and
> r_cast_id(T2) times to the right. Whenever
>   (r_cast_id(T1)-r_cast_id(T2))%number_of_bits !=3D0,
> things get weird.
Apart from breaking C compatibility for pointers to POD types (5.4/5
says that, barring const_cast, C-style cast is equivalent to reinterpret_=
cast,
unless static_cast is possible), such an implementation would clearly vio=
late
(s3) of 5.2.10/10 that you cited below!
For structures, there is the additional requirement in 9.2/17
"A pointer to a POD-struct object, suitably converted using a reinterpret=
_cast,
 points to its initial member [...] and vice versa."

>=20
> > Casting from one type to another and back to the original type would
> > then work properly and the above cast would not do anything useful.
> >
> > QoI says it will work as expected.  If paranoid,
> >
> >    char* ptr =3D &reinterpret_cast<char&>( my_data );
> >
> > uses 5.2.10/10 and must work.
> >
> > John
>=20
> Well, if paranoid, try some union workaround. To explain
> why I'll split 5.2.10/10 to sentences and try to interpret
> each one in order of appearance.
>=20
> (s1) An lvalue expression of type T1 can be cast to the type
> ``reference to T2'' if an expression of type ``pointer to T1''
> can be explicitly converted to the type ``pointer to T2'' using
> a reinterpret_cast.
>=20
> This says which r_casts of references are valid.
>=20
> (s2) That is, a reference cast reinterpret_cast<T&>(x) has
> the same effect as the conversion *reinterpret_cast<T*>(&x)
> with the built-in & and * operators.
>=20
> This sentence starts with "that is," which makes it look like
> an explanation of (s1). However, the rest of the sentence
> is clearly not an explanation of (s1), it's rather the full
> definition of r_cast behaviour.
>=20
> (s3) The result is an lvalue that refers to the same object as
> the source lvalue, but with a different type.
>=20
> Given that we already have the definition of r_cast's
> behaviour, this must be the definition of the phrase
> "to point to the same object, but with a different type".
This seems pretty clear to me - it gives an additional constraint
for the implementation of reference reinterpret_cast, and hence
indirectly, because of (s2), also for the pointer reinterpret_cast
- meaning that the source and destination pointer shall point to
the same object, unless this is impossible due to alignment issues.

>=20
> (s4) No temporary is created, no copy is made, and
> constructors (class.ctor) or conversion functions (class.conv)
> are not called.
>=20
> This is clear and needs no explanation.
>=20
> Summary: The r_cast of a pointer need not point to the same
>     memory location, it is implementation defined. The r_cast
>     of a reference is defined by means of r_cast of a pointer
>     and thus the result may be a reference to a different
>     memory location as well.
See (s3): the cast result shall refer to the same object as the source
l-value, and in an analogous manner, source and result pointer shall
point to the same object. Of course, depending on machine architecture,
this may not work if the source object is not properly aligned for the
destination type - and that's the only reason why 5.2.10/3 and 5.2.10/7
are not clearer than they are :-). To cite James Kanze
<http://groups.google.com/groups?hl=3Dde&lr=3D&ie=3DUTF-8&selm=3Dd6652001=
.0405050136.670d0f99%40posting.google.com>
(in comp.lang.c++.moderated from 2004-05-05 03:50:05 PST):
"I have no doubt that the intent of the standard is for the
 reinterpret_cast to work in this case; all of the wishy-washy wording is
 there to allow things like reinterpret_cast<int*> not to work, or to
 give funny results, say on machines where int* is smaller than a char*."

In case the alignment requirements are met (i.e. always, if you cast
to char& or unsigned char&, respectively to char* or unsigned char*),
referring/pointing to the same object IMO clearly implies referring/point=
ing
to the same memory location. Am I mistaken?

Best regards
Falk

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: wade@stoner.com (Bill Wade)
Date: Sat, 29 May 2004 15:48:50 +0000 (UTC)
Raw View
alan_mckenney1@yahoo.com (Alan McKenney) wrote in message news:<16a885f9.0405270933.1e05001e@posting.google.com>...

I asked the same question recently.

> Is the naive implementation legal?  Or does the
> standard require that the bit representation of
> a pointer be changed to point to (more or less)
> the same memory, at least when casting to
> char *?

Falk Tannh   user provided answers

Answer 1:

  int i;
  (char*)&i;

This is an alternate syntax for reinterpret cast in C++.  The C style
cast works in C.  Is it allowed to be broken in C++?

Answer 2:

5.2.10/10 strongly implies a standard requirement when the pointer is
not null.

1) The pointer cast is legal (5.2.10/7).
2) The lvalue cast of 5.2.10/10 has the same "effect" as the pointer
cast.
3) "The result [of the lvalue cast] refers to the same object ... but
with a different type."

5.2.10/8 gives the standard requirement for null pointers.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Michiel.Salters@logicacmg.com (Michiel Salters)
Date: Tue, 1 Jun 2004 17:06:34 +0000 (UTC)
Raw View
alan_mckenney1@yahoo.com (Alan McKenney) wrote in message news:<16a885f9.0405270933.1e05001e@posting.google.com>...
> In some C++ groups, people recommend outputing
> random data by doing something like:
>
>      POD_type my_data;
>      ....
>      char *ptr = reinterpret_cast<char *>( &my_data );
>
> This generally works on the more popular architectures,
> such as SPARC, Intel, etc., but is it *required* to work?

Yes, for char* and unsigned char*. PODs may be read via expressions
of char type (3.10/15), and the meaning of the cast is given by
5.2.10/10. The pointer must refer to the same object.

Regards,
Michiel Salters

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Tue, 1 Jun 2004 19:57:26 +0000 (UTC)
Raw View
On Tue, 1 Jun 2004 17:06:34 +0000 (UTC), Michiel.Salters@logicacmg.com
(Michiel Salters) wrote:

> alan_mckenney1@yahoo.com (Alan McKenney) wrote in message news:<16a885f9.0405270933.1e05001e@posting.google.com>...

> > In some C++ groups, people recommend outputing
> > random data by doing something like:

> >      POD_type my_data;
> >      ....
> >      char *ptr = reinterpret_cast<char *>( &my_data );

> > This generally works on the more popular architectures,
> > such as SPARC, Intel, etc., but is it *required* to work?

> Yes, for char* and unsigned char*. PODs may be read via expressions
> of char type (3.10/15), and the meaning of the cast is given by
> 5.2.10/10. The pointer must refer to the same object.

Wrong reference.  5.2.10/10 is about reference casts which are not used
here.

   char& ref(reinterpret_cast<char&>(my_data);

Since 5.2.10/7 states that the above pointer cast is well formed, the
reference cast would also be well formed and then by 5.2.10/10 says
that it refers to the same object.

Note that 5.2.10/10 does not say that the well formed pointer cast will
produce a pointer to the same object.  It would be valid for the
implementation to flip all bits on all pointer reinterpret_casts.
Casting from one type to another and back to the original type would
then work properly and the above cast would not do anything useful.

QoI says it will work as expected.  If paranoid,

   char* ptr = &reinterpret_cast<char&>( my_data );

uses 5.2.10/10 and must work.

John

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Falk =?iso-8859-1?Q?Tannh=E4user?= <falk.tannhauser@crf.canon.fr>
Date: Wed, 2 Jun 2004 12:29:33 CST
Raw View
John Potter wrote:
>
> On Tue, 1 Jun 2004 17:06:34 +0000 (UTC), Michiel.Salters@logicacmg.com
> (Michiel Salters) wrote:
>
> > Yes, for char* and unsigned char*. PODs may be read via expressions
> > of char type (3.10/15), and the meaning of the cast is given by
> > 5.2.10/10. The pointer must refer to the same object.
>
> Wrong reference.  5.2.10/10 is about reference casts which are not used
> here.
>
>    char& ref(reinterpret_cast<char&>(my_data);
>
> Since 5.2.10/7 states that the above pointer cast is well formed, the
> reference cast would also be well formed and then by 5.2.10/10 says
> that it refers to the same object.
>
> Note that 5.2.10/10 does not say that the well formed pointer cast will
> produce a pointer to the same object.  It would be valid for the
> implementation to flip all bits on all pointer reinterpret_casts.
> Casting from one type to another and back to the original type would
> then work properly and the above cast would not do anything useful.
But 5.2.10/10 also says: "... a reference cast reinterpret_cast<T&>(x)
has the same effect as the conversion *reinterpret_cast<T*>(&x) with
the builtin & and * operators."
Thus, while 5.2.10/7 doesn't explicitly state that the casted pointer
points to the same object as the original one, this "canonical
relationship" between pointer and reference casts, taken together
with the requirement of 5.2.10/10 "The result is an lvalue that refers
to the same object as the source lvalue, but with a different type."
implies to me that the pointer cast is guaranteed to work as expected.

Falk

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: alan_mckenney1@yahoo.com (Alan McKenney)
Date: Thu, 27 May 2004 18:02:59 +0000 (UTC)
Raw View
In some C++ groups, people recommend outputing
random data by doing something like:

     POD_type my_data;
     ....
     char *ptr = reinterpret_cast<char *>( &my_data );

This generally works on the more popular architectures,
such as SPARC, Intel, etc., but is it *required* to work?

That is, does "reinterpret_cast<>" of a pointer *necessarily*
result in something that is a valid pointer to anything at all?
E.g., in:

    int i;
    char *cp = reinterpret_cast<char *>(&i);

are we guarranteed that "cp" points to anything near
"i"?



This becomes an issue on a machine like a CRAY-XMP, where
the smallest directly addressable memory is a 64-bit word,
and characters are packed 8 to a word.

"int *" is implemented as a memory address, while
"char *" is implemented as

    ( memory_address << 3 ) | ( byte_no_within_word )


The naive implementation of reinterpret_cast<char *>(&i)
(use the same bit represenation) would result in a
pointer to a completely different word.

If the address of i is 0x10000, then cp would point
to byte 0 in word 0x2000.


Is the naive implementation legal?  Or does the
standard require that the bit representation of
a pointer be changed to point to (more or less)
the same memory, at least when casting to
char *?

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]