--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
// I guess you don't mean this:
// (not sure if the first one compiles though)
int x = 42;
double d1 = static_cast<double const&>(x);
double d2 = reinterpret_cast<double const&>(x);
Anyway:
Typically, reinterpret_cast only changes the pointer/reference type, but
leaves the pointer value alone. The standard says that what it does is
implementation defined. static_cast only allows the additional conversion
from base to derived pointer/reference.
That means that if the source and target object of the cast don't have the
same address, e.g. in the case of multiple inheritance, the behaviour might
be different.
As a general rule, avoid reinterpret_cast because it performs too many
conversions and that makes it rather unsafe. If you can use static_cast, do
so. If you can live without explicit casts, that's even better. When using
reinterpret_cast, I prefer not to use the result for anything but
storing/transferring and then use a reinterpret_cast back to the original
type in order to use it.
Uli
> I recently had a little chat with someone who seemed to think that one
> could get different runtime behavior in some cases with the use of
> static_cast vs. reinterpret_cast. Is that correct? I can't personally
> think of an example of such a thing. I've always thought that the
> differences where purely compile-time differences.
Sure.
double value = ...;
int rounded = static_cast<int>(value + 0.5);
This certainly results in differing runtime behavior, depending on the
contents of value.
--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM, Y!M erikmaxfrancis
To love without criticism is to be betrayed.
-- Djuna Barnes
Multiple Inheritance.
You mean like this?
#include <iostream>
int main(int argc,char**argv) {
double a=10.3;
std::cout<<a<<std::endl;
std::cout<<static_cast<int>(a)<<std::endl;
std::cout<<reinterpret_cast<int&>(a)<<std::endl;
}
bye
av.
You should never use reinterpret_cast unless you know what the
consequences will be and what platform/implementation your code will be
used for.
Note that there is a very different meaning to the two casts.
static_cast<T> effectively means extract a T by value from the result of
the following expression whereas reinterpret_cast<T> means 'use the
result of evaluating the following expression as a T.
--
Note that robinton.demon.co.uk addresses are no longer valid.
Unfortunately, one does not always have a viable alternative.
One place where we end up having to use
reinterpret_cast<> a lot is for converting between
pointers to plain char and unsigned char. (The critical word
is "pointers".)
Unfortunately, C++ considers "char" and "unsigned char"
to be unrelated types as far as pointers to them go, so you can't
do static_cast<const char *> on a "const unsigned char *"
So far, I know of no alternative that doesn't copy the data
(which we can't afford.)
Fortunately, on the architectures I am familiar with,
I can't think how this wouldn't work unless the implementation
was deliberately trying to break it.
> Sure.
>
> double value = ...;
> int rounded = static_cast<int>(value + 0.5);
>
> This certainly results in differing runtime behavior, depending on the
> contents of value.
I think you've misunderstood me.
Damien-Kicks-Computer:~/tmp dkick$ cat duff.cc
void f()
{
double value = 3.14159265;
int x = static_cast<int>(value + 0.5);
int y = reinterpret_cast<int>(value + 0.5);
}
Damien-Kicks-Computer:~/tmp dkick$ g++ -c duff.cc
duff.cc: In function 'void f()':
duff.cc:5: error: invalid cast from type 'double' to type 'int'
Damien-Kicks-Computer:~/tmp dkick$
Here, the difference between static_cast and reinterpret_cast is a
compile-time difference, as I would expect. I am looking for an example
where the static_cast and reinterpret_cast of the same expression to the
same type both compile but produce different results at runtime.
--
Not really. In my mind, these are different casts, i.e. the types of
the casts are different. "static_cast<int&>(a)" and
"reinterpret_cast<int&>(a)" or "static_cast<int>(a)" and
"reinterpret_cast<int>(a)" producing different run-time results is the
kind of thing for which I'm looking. However, either
"static_cast<int&>(a)" or "reinterpret_cast<int>(a)" are not going to
compile, i.e. different behavior at compile-time.
I was under the impression that dynamic_cast is the only cast which can
safely be used for a class with a virtual base, i.e. static_cast and
reinterpret_cast are equally unsafe in such a case.
> You should never use reinterpret_cast unless you know what the
> consequences will be and what platform/implementation your code will be
> used for.
Sure sure... the best answer to the question is probably "why do you
want to use reinterpret_cast in the first place?"
> Note that there is a very different meaning to the two casts.
> static_cast<T> effectively means extract a T by value from the result of
> the following expression whereas reinterpret_cast<T> means 'use the
> result of evaluating the following expression as a T.
I'm having a hard time, though, coming up with an example where I can
get different run-time behavior from "the same cast", i.e. casting the
same expression to the same type, with the only difference being between
static_cast and reinterpret_cast. For example, with you're hint, I
tried the following:
Damien-Kicks-Computer:~/tmp dkick$ cat duff.cc
#include <iostream>
#include <ostream>
class X {
int y_;
int z_;
public:
X(int y, int z) : y_(y), z_(z) { }
operator int() const { return y_ + z_; }
};
int main()
{
X x(13, 69);
std::cout << static_cast<int>(x) << '\n';
#if 0
// These two statements will not compile...
std::cout << reinterpret_cast<int>(x) << '\n';
std::cout << *static_cast<int*>(&x) << '\n';
#endif
std::cout << *reinterpret_cast<int*>(&x) << '\n';
}
Damien-Kicks-Computer:~/tmp dkick$ g++ duff.cc -o duff
Damien-Kicks-Computer:~/tmp dkick$ ./duff
82
13
Damien-Kicks-Computer:~/tmp dkick$
But I can only get this example to work if I use "different casts", i.e.
something about the type or the expression has to be different.
--
> I recently had a little chat with someone who seemed to think that one
> could get different runtime behavior in some cases with the use of
> static_cast vs. reinterpret_cast. Is that correct? I can't personally
> think of an example of such a thing. I've always thought that the
> differences where purely compile-time differences.
A static_cast and a reinterpret_cast can certainly certainly produce
differing results - even when even when casting the same operand to the same
type. The reason why the casts would differ is that a reinterpret_cast tells
the compiler that the programmer knows more about the cast than the
compiler. So the compiler when applying a reinterpret_cast ignores what it
knows about the types involved, and does not perform whatever adjustments
that it would have performed for a static_cast with identical arguments.
So - unless the programmer really does know more than the compiler about a
particular cast, the consequences of applying a reinterpret_cast can be
disastrous:
#include <iostream>
struct A1 { int a; };
struct A2 { double d; };
struct B : public A1, A2
{
int v;
};
int main()
{
// one B object
B b;
// two A2 pointers
A2 * p1;
A2 * p2;
// set both pointers to &b
p1 = static_cast<A2*>(&b);
p2 = reinterpret_cast<A2*>(&b);
// same type, same B object...
// but point to different addresses:
std::cout << "p1: " << p1 << "\n";
std::cout << "p2: " << p2 << "\n";
// the pointers are not equal
assert (p1 == p2); // fails
}
Program Output:
p1: 0xbffff97c
p2: 0xbffff978
Assertion failed: (p1 == p2), function main, file test.cc, line 30.
Abort trap
Greg
char* pc;
void* pv = pc; // = static_cast<void*>(pc);
unsigned char* puc = static_cast<unsigned char*>(pv);
> Unfortunately, C++ considers "char" and "unsigned char"
> to be unrelated types as far as pointers to them go, so you can't
> do static_cast<const char *> on a "const unsigned char *"
> So far, I know of no alternative that doesn't copy the data
> (which we can't afford.)
Yes, it is annoying that this can't be done in a single step, in particular
because C++ guarantees that every object can be represented as a sequence
of unsigned char (or was it plain char?).
> Fortunately, on the architectures I am familiar with,
> I can't think how this wouldn't work unless the implementation
> was deliberately trying to break it.
IIRC, reinterpret_cast eventually does the same as a C-style cast, except
that it leaves CV-qualifiers alone. Since C-style casts are rather
well-defined, so is reinterpret_cast and I also don't think it will break
anywhere. I think that one intention was that reinterpret_cast should be
allowed to change the representation, e.g. for imaginary architectures
where pointers are multiplied by the pointee's size for dereferencing
(rather like indices in C/C++). I'm not aware of any case where that is
used though.
Uli
--
Sator Laser GmbH
Geschäftsführer: Ronald Boers, Amtsgericht Hamburg HR B62 932
> Unfortunately, C++ considers "char" and "unsigned char"
> to be unrelated types as far as pointers to them go, so you can't
> do static_cast<const char *> on a "const unsigned char *"
Yes...
> So far, I know of no alternative that doesn't copy the data
I am using in these cases static cast(s), however, it does
not make things really better:
static_cast<const char *>(static_cast<const void *>(...))
This gets rid of the reinterpret cast, and covers the undefined
behaviour a little bit ;-)
Best regards,
Kurt.
[snip]
> I'm having a hard time, though, coming up with an example where I can
> get different run-time behavior from "the same cast", i.e. casting the
> same expression to the same type, with the only difference being between
> static_cast and reinterpret_cast.
[...]
Try:
#include <iostream>
#include <cstddef>
struct A {
int i;
};
struct B {
int j;
};
struct D : public A, public B {};
std::ptrdiff_t offset_diff ( void* a, void* b ) {
return ( reinterpret_cast< std::size_t >( a ) -
reinterpret_cast< std::size_t >( b ) );
}
int main ( void ) {
D d;
A* a_ptr = &d;
B* b_ptr = &d;
D* d_ptr = &d;
std::cout
<< offset_diff ( static_cast<D*>( a_ptr ),
static_cast<D*>( d_ptr ) ) << '\n'
<< offset_diff ( static_cast<D*>( b_ptr ),
static_cast<D*>( d_ptr ) ) << '\n'
<< offset_diff ( reinterpret_cast<D*>( a_ptr ),
reinterpret_cast<D*>( d_ptr ) ) << '\n'
<< offset_diff ( reinterpret_cast<D*>( b_ptr ),
reinterpret_cast<D*>( d_ptr ) ) << '\n';
}
On my machine:
0
0
0
4
Best
Kai-Uwe Bux
Damien Kick wrote:
> I recently had a little chat with someone who seemed to think that one
> could get different runtime behavior in some cases with the use of
> static_cast vs. reinterpret_cast. Is that correct?
Yes. The cast operators do have different runtime behavior. Consider for
example
struct B {};
struct D : public B {};
int main()
{
B b;
B *p1 = static_cast<B*>(static_cast<D*>(&b));
// undefined behavior as b is not a sub-object of some D
B *p2 = reinterpret_cast<B*>(reinterpret_cast<D*>(&b));
// no problem here
}
There are also "visible" differences (or at least they are very likely
to be visible). The following example is likely to print different
values for the two different casts:
#include <iostream>
#include <ostream>
struct A { char x; };
struct B { char x; };
struct D : public A, public B {};
int main()
{
D d;
std::cerr << reinterpret_cast<char*>(&d) << "\n";
std::cerr << static_cast<char*>(&d) << "\n";
}
Markus
There was a recent thread on this, and the general
conclusion was that your double static_cast was no
better than reinterpret_cast<> in terms
how well-defined the behavior is.
Actually, I would expect the simple reinterpret_cast<>
to be more reliable, since it provides the information
(source and target type) to the compiler in a more
direct way. If it's a cast that the compiler writers
are familiar with (such as unsigned T* <-> signed T*
or T* <-> char*), they are more likely to make sure it
works as expected.
I also believe that "undefined behavior" is, if actually
in the Standard, misleading. I would think that
"implementation-defined behavior" is closer
to the truth, if we allow the implementation
definition to say "not allowed" in some cases.
The whole point of reinterpret_cast<> is to allow
casts whose behavior the Standard can't define for all
implementations, but which can be used safely if
used with care and some knowledge of the platform
being used.
You cannot use static_cast to convert a D* into a char* here;
this is an ill-formed program that won't compile.
> }
For your purpose, it is sufficient to cast &d either into A* or into B*;
one of them will print different values. For example, when I try
std::cerr << reinterpret_cast<B*>(&d) << "\n";
std::cerr << static_cast<B*>(&d) << "\n";
on gcc-4.1.3 on Linux on i686, I get the following result:
0xbfdc5c72
0xbfdc5c73
--
Seungbeom Kim
According to 5.2.9/2, a static_cast of the form "static_cast<T>(e)" is
allowed if the declaration "T t(e);" is well-formed, and it is the same as
declaring, initializing and then using the temporary variable 't' as
follows:
int x = 42;
const double& t(x);
double d1 = t;
The declaration "const double& t(x);" is well-formed according to 8.5.3/5,
but it wouldn't be if the type of the reference were non-const. So the code
should compile, while the following shouldn't:
int x = 42;
double d1 = static_cast<double&>(x); // Note: reference not const.
This is in fact confirmed by Visual C++ 2005 Express Edition, which in both
cases (const and non-const) behaves just as required by the standard.
> double d2 = reinterpret_cast<double const&>(x);
According to 5.2.11/10, this is also well-defined, but produces a different
result than the static_cast: "No temporary is created, no copy is made, and
constructors (12.1) or conversion functions (12.3) are not called." While
the static_cast converts the integer representation of 42 to its floating
point representation, the bit pattern is left unchanged with the
reinterpret_cast, only the type changes, and thus the way it is interpreted.
I am amazed that the static_cast in the example above works, however. After
all, a reference of type double is bound to an object of type int, so if the
object is accessed through the reference, how is the compiler supposed to
know that the referenced bit pattern is an interger representation? It seems
like Visual C++ 2005 Express Edition creates a temporary variable of type
double from 'x' and binds 't' to it. But isn't there a requirement that any
modification of the value stored in 'x' also affects the value referenced by
't'? Please take a look at the following code:
int x = 42;
const double& t(x);
std::cout << "Value of x is: " << x << std::endl;
std::cout << "Value of t is: " << t << std::endl;
std::cout << "Address of x is: " << &x << std::endl;
std::cout << "Address of t is: " << &t << std::endl;
++x;
std::cout << "Value of x is: " << x << std::endl;
std::cout << "Value of t is: " << t << std::endl;
On Visual C++ 2005 Express Edition, the output I get is the following:
Value of x is: 42
Value of t is: 42
Address of x is: 0012F3D0
Address of t is: 0012F3C8
Value of x is: 43
Value of t is: 42
Is this the behaviour required by the standard?
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
I remember a thread on this issue some time ago where the general conclusion
was that according to the standard, it is well-defined to convert a pointer
to any type to a pointer to char using the following functions:
// Converts a pointer of any non-const
// type to a non-const char pointer.
inline char* char_ptr( void* p ) throw()
{ return static_cast<char*>( p ); }
// Converts a pointer of any constant
// type to a constant char pointer.
inline const char* char_ptr( const void* p ) throw()
{ return static_cast<const char*>( p ); }
Example:
int main()
{
SomeObject* pobj = ...;
const int* pint = ...;
// Convert non-const pointer.
char* p1 = char_ptr( pobj );
// Convert const pointer.
const char* p2 = char_ptr( pint );
return 0;
}
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
Yes. How else could this program behave? "t" is a reference to a
double - and since "x" is not a double (but is in fact a completely
unrelated type), "x" cannot be the variable of type double that "t" is
referencing.
Instead, "t" refers to a temporary variable (of type double) that was
initialized with "x"'s value (42). And since there is no way for the
program to access this temporary, its value will remain at 42.0 for
the life of the program. Which is just as well - given that "t" is
declared const. (In fact "t" must be declared const here because
binding a non-const reference to a temporary is not allowed).
Greg
--
I just had another look at 8.5.3/5 to learn that you are right. When I read
it yesterday, I got confused because of all the bullets, sub-bullets and
conditions involved with each of them. The behaviour described above is
indeed required by the very last bullet: "Otherwise, a temporary of type
'cv1 T1' is created and initialized from the initializer expression using
the rules for a non-reference copy initialization (8.5). The reference is
then bound to the temporary."
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers