Topic: Portable reinterpret_casts [was: cast operator]


Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Thu, 21 Nov 2002 17:58:43 +0000 (UTC)
Raw View
On Thu, 21 Nov 2002 17:04:35 +0000 (UTC), jpotter@falcon.lhup.edu
(John Potter) wrote:

>(Gennaro Prota) wrote:
>
>> (John Potter) wrote:
>
>> >reinterpret_cast<double&>(a) = 10;
>> >Would be prefered in C++ which is still the same as
>> >*reinterpret_cast<double*>(&a) = 10;
>
>> A few days ago there was a discussion about this on the boost list.
>> The goal there was to understand whether the boost definition of
>> addressof is guaranteed to work on all conforming implementations.
>
>5.2.10/3 is quite clear in making almost nothing portable.  However,
>5.2.10/4-5 is quite clear that the implementation is expected to do
>something reasonable.

Yes, I do understand that. But I'm under the impression that 5.2.10/7
leaves too much to reasonableness, in that it makes almost everything
unspecified whereas there are cases (like reinterpret_casts to char or
unsigned char) that should be IMHO explicitly defined. I have pasted
here my last post in the boost thread, where I think my position may
appear clearer (To give you some context: it is part of a thread about
CopyConstructible. Doug has submitted a DR where he states that the
requirement, part of CopyConstructible, that &t returns the address of
t with type T* is overly strict because the address of an object can
be anyway obtained *portably* with

  template <typename T> T* addressof(T& v)
  {
    return reinterpret_cast<T*>(
     &const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
  }

My position is that by reading the standard I don't feel strong enough
to make such an assertion, though it is "reasonable".
)

----------------------------------

On Wed, 20 Nov 2002 10:00:14 -0500, Douglas Gregor <gregod@cs.rpi.edu>
wrote:

>On Saturday 16 November 2002 12:24 pm, Gennaro Prota wrote:
>> Sorry for the late reply (it's just my timezone).
>>
>> You wrote:
>> >I don't see the contradiction here. 5.2.10/7 says that you can cast from a
>> > T pointer to a U pointer and back to a T pointer and get the original
>> > pointer back.
>>
>> Unfortunately the standard is a great piece of work but fails
>> miserably to support you when you want to "deduce" things that are not
>> written explicitly there in plain English, especially when generic
>> expressions like "it's the same as", "is equivalent to", etc. are
>> used.
>
>I would generally agree that such an informal style doesn't allow any
>deduction, but I think we have to be realistic. We don't have a formal
>specification for C++, and it's unlikely that we will ever have one. We won't
>get anywhere if we require formal methods with an informal specification.


But, as you have seen, I wasn't applying formal methods. However I'm
particularly careful at not reading too much in the standard. My
position is different from yours however. You are one of the people
involved in the standardization {Note: Yes, I thought Doug was in the
committee. My mistake} so you may be in the position of
knowing what they wanted to write, instead of what *is* written. You
see that from my perspective instead, if I read that everything I can
do with the value of reinterpret_cast is to cast it back to its
original type I try to not do anything else :-) By following
comp.std.c++ for a while I've learnt that there are a lot of cases
where the behavior is left unspecified exactly because there are
architectures where the behavior is not the "obvious" one the naive
programmer would expect (for instance, because they do "unusual"
hardware checks)


Frankly I don't know if there's some strange (but conforming)
implementation of references that can cause problems with the chain of
casts:

   reinterpret_cast<T*>(
         &const_cast<char&>(
           reinterpret_cast<const volatile char &>(v)));


The writers of the standard probably know though.


>> First of all the quotes:
>>
>>    5.2.10/7: "A pointer to an object can be explicitly converted
>>    to a pointer to an object of different type.65) Except that
>>    converting an rvalue of type "pointer to T1" to the type
>>    "pointer to T2" (where T1 and T2 are object types and where
>>    the alignment requirements of T2 are no stricter than those
>>    of T1) and back to its original type yields the original pointer
>>    value, the result of such a pointer conversion is unspecified."
>>
>>
>> Incidentally, what does "converting back" means? However that's not
>> the main point.
>
>Given T* tp, reinterpret_cast<T*>(reinterpret_cast<U*>(tp)) is semantically
>equivalent to tp.

In that form, verbatim, yes. The problems begin when you put something
in the middle.


>>    5.2.10/10: 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. 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.
>>
>>
>> What does it mean "has the same effect of"?
>
>Would you prefer "is semantically equivalent to?" You can rewrite one
>expression as the other. (Not in actual C++ code, because you can't say "I
>want the built-in operator&", but it's fine for exploring the properties of
>an expression).

But with a built-in you can be sure that & has the built-in meaning,
and I'm not sure that

   double d = 2.0;
   *reinterpret_cast<int*>(d);

is ok either (and not because of alignment issues).


>> 5.2.10/7 says that the
>> result of reinterpret_cast<T*>(&x) is unspecified. What is the effect
>> of dereferencing it?
>>
>>     *reinterpret_cast<T*>(&x)
>
>The effect is the same as dereferencing any pointer. You get the lvalue
>associated with the address stored in the pointer.


I think everybody realizes what happens in terms of expressions (i.e.
in terms of sequences of signs written in the program text). The issue
IMHO is what kind of code the compiler is authorized to generate; the
type T could have, for instance, padding at the beginning: is it ok to
"dereference"? Are there architectures that would trap the attempt?

Come to think of it, the situation of addressof is similar to

    &array[array_size]

which is undefined behavior but is usually ok because no access past
the end is actually made.

Another example: suppose the implementation tags the result of
reinterpret_cast<U*> as "unusable except for pointer-casting". As long
as it uses an injective function for the mapping so that the cast-back
works as expected, is it conforming?


In conclusion, I think it's not a matter of what is written in the
standard but of what "should" be. The current wording is IMHO too weak
to give an answer here. But it can be changed according to the intent.
Off the top of my head I would say the requirements of

   *reinterpret_cast<U*> (x)

should be the same as

    reinterpret_cast<U&> (x)

which is exactly the problem: you should be able to do type punning
with both forms, and in some cases the type punning should be
portable. One form that I think should be portable is indeed the
reinterpret_cast to char and unsigned char: according to 3.10/15 it
seems (I say "it seems" because actually the text says the behavior is
undefined for the types *not* in the list, not that it is defined for
the types that are in the list) that I can access the value of an
object through an lvalue of char type but I don't see any portable way
to obtain such an lvalue. I would say that's a hole in the standard.
What do you think?

_______________________________________________
Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost

----------------------------------


PS: I have snipped the rest of your post in order to keep this
reasonably short (well, as far as possible). What intrigued me was the
part where you ask me if I was thinking to an lvalue to rvalue
conversion after dereferencing. I do know that dereferencing produces
an lvalue. What was exactly your point?

Genny.

---
[ 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: "Zaza" <francesco.fassi.agos@libero.it>
Date: Fri, 22 Nov 2002 12:25:27 CST
Raw View
Thanks.

---
[ 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                       ]