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...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
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.
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
> alan_mc...@yahoo.com (Alan McKenney) wrote in message news:<16a885f9.04052...@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
Falk
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
given that the pointer has _even_ number of bits...
Sorry for that mistake.
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.
>
> (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.
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=de&lr=&ie=UTF-8&selm=d6652001.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/pointing
to the same memory location. Am I mistaken?
Best regards
Falk
The C standard does not specify where a pointer points when it is
converted to a pointer to an unrelated non-character type. The only
thing it says is that the new pointer, if converted back to the
original type, must compare equal to the original pointer value.
The C standard does specify, for instance, that converting a pointer
to a structure type into a pointer to the type of it's first member
produces a pointer to that member of the structure pointed at by the
original pointer. Similar guarantees apply to unions and arrays.
That's what I meant by "related types". However, for unrelated types
there's no guarantees.