Author Topic: cast and static cast  (Read 11719 times)

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
cast and static cast
« on: December 09, 2005, 04:42:45 pm »
BTW, what's the difference between static_cast<type*>(pointer) and (type*)(pointer) ? I never understood it.
I must admit: I too :).
But it seems that static-cast is safer that the C style of cast. Have a look at what BS says:

http://www.research.att.com/~bs/bs_faq2.html#static-cast

Michael

Offline Urxae

  • Regular
  • ***
  • Posts: 376
Re: cast and static cast
« Reply #1 on: December 09, 2005, 04:49:28 pm »
BTW, what's the difference between static_cast<type*>(pointer) and (type*)(pointer) ? I never understood it.

It is the same:

(type*)(pointer)  C way
static_cast<type*>(pointer)  C++ way

Sorry, not true.
Code: [Select]
class A {};
class B {};

int main()
{
    A a;
    B b;
    A* pa = &a;
    B* pb1 = (B*) pa;               // allowed, but don't do this
    B* pb2 = static_cast<B*>(pa);   // not allowed
}

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: cast and static cast
« Reply #2 on: December 09, 2005, 05:08:59 pm »
Code: [Select]
class A {};
class B {};

int main()
{
    A a;
    B b;
    A* pa = &a;
    B* pb1 = (B*) pa;               // allowed, but don't do this
    B* pb2 = static_cast<B*>(pa);   // not allowed
}
But you can:

Code: [Select]
B* pb2 = reinterpret_cast<B*>(pa);

Or?


Offline Urxae

  • Regular
  • ***
  • Posts: 376
Re: cast and static cast
« Reply #3 on: December 09, 2005, 05:19:39 pm »
Code: [Select]
[...]
    B* pb1 = (B*) pa;               // allowed, but don't do this
    B* pb2 = static_cast<B*>(pa);   // not allowed
[...]
But you can:

Code: [Select]
B* pb2 = reinterpret_cast<B*>(pa);

Yes you can, that's the equivalent of the pb1 line. So in general, don't do that either ;) (but prefer it over the pb1 way if you really need to do something like this).

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: cast and static cast
« Reply #4 on: December 09, 2005, 05:29:50 pm »
Yes you can, that's the equivalent of the pb1 line. So in general, don't do that either ;) (but prefer it over the pb1 way if you really need to do something like this).
Yes, I agree. I try to avoid casts, because most of the time they just bring errors difficult to find and debug. And as BS concludes in his static-cast FAQ topic...

Quote
Maybe, because static_cast is so ugly and so relatively hard to type, you're more likely to think twice before using one? That would be good, because casts really are mostly avoidable in modern C++.

Offline takeshi miya

  • Lives here!
  • ****
  • Posts: 1487
Re: cast and static cast
« Reply #5 on: December 09, 2005, 05:52:45 pm »
Sorry, not true.
Code: [Select]
class A {};
class B {};

int main()
{
    A a;
    B b;
    A* pa = &a;
    B* pb1 = (B*) pa;               // allowed, but don't do this
    B* pb2 = static_cast<B*>(pa);   // not allowed
}

Sorry, I was trying to mean
(type)(variable)  C way
static_cast<type>(variable)  C++ way

Offline Urxae

  • Regular
  • ***
  • Posts: 376
Re: cast and static cast
« Reply #6 on: December 09, 2005, 08:44:58 pm »
Sorry, I was trying to mean
(type)(variable)  C way
static_cast<type>(variable)  C++ way

But you claimed they were the same, which wasn't true. They're similar, but static_cast<> is safer.

Offline rickg22

  • Lives here!
  • ****
  • Posts: 2283
Re: cast and static cast
« Reply #7 on: December 09, 2005, 09:19:25 pm »
:-o

OK, thanks :) I guess that answers my question.

Offline takeshi miya

  • Lives here!
  • ****
  • Posts: 1487
Re: cast and static cast
« Reply #8 on: December 10, 2005, 03:28:25 am »
But you claimed they were the same, which wasn't true. They're similar, but static_cast<> is safer.

Thanks, I didn't know that it was safer in that sense, I thought that it was safer for academic reasons. :P

Offline me22

  • Official tester
  • Multiple posting newcomer
  • ***
  • Posts: 53
    • TA Universe
Re: cast and static cast
« Reply #9 on: December 10, 2005, 09:02:23 am »
The nicest example I've seen is switching implementation styles.

You initially used Employee* as your handle type, but you change it to unsigned ints for some reason.  The compiler catches most of the changes, but you have one hidden issue:
Code: [Select]
void Employee::setManager(handle new_manager) {
    manager_.removeSubordinate( this );
    manager_ =  (Manager*)new_manager;
    manager_.addSubordinate( this );
}
Now this is bad code on multipule levels ( not exception safe, for example ) but that cast is evil.  The compiler will not longer care that the cast has changed from a fairly acceptable, though unsafe, downcast to a completely meaningless integer reinterpretation.

Note that in C++, c-style casts are actually defined in terms of a complex sequence of the named casts.

static_cast : innocent casts.  Derived* to Base*, int to float, etc
const_cast : adding or removing const -- no other named casts allow this, which is a good thing
dynamic_cast : checked Base* to Derived*
reinterpret_cast : to be avoided.  Only useful for passing T* as the data argument of a C callbacks, since any use other than casting T* to U* and back to T* is undefined or implementation-defined.

Here's another instructive demo:
Code: [Select]
#include <iostream>

struct B { char c; };
struct D : B { char a; };

int main() {
    D d;
    std::cout << &d << std::endl;
    std::cout << (B*)&d << std::endl;
    std::cout << static_cast<B*>(&d) << std::endl;
    std::cout << reinterpret_cast<B*>(&d) << std::endl;
    std::cout << (void*)&d << std::endl;
    std::cout << static_cast<void*>(&d) << std::endl;
    std::cout << reinterpret_cast<void*>(&d) << std::endl;
}
« Last Edit: December 10, 2005, 09:06:20 am by me22 »

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: cast and static cast
« Reply #10 on: December 10, 2005, 07:29:00 pm »
static_cast : innocent casts.  Derived* to Base*, int to float, etc
IMHO, no cast is innocent.

Michael

Offline me22

  • Official tester
  • Multiple posting newcomer
  • ***
  • Posts: 53
    • TA Universe
Re: cast and static cast
« Reply #11 on: December 10, 2005, 08:03:45 pm »
IMHO, no cast is innocent.

not even static_cast<T*>(0)?

zero matches int overloads or specialisations, so...

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: cast and static cast
« Reply #12 on: December 10, 2005, 08:15:30 pm »
not even static_cast<T*>(0)?
zero matches int overloads or specialisations, so...
Nice :), but useful for?

In the limit of the possible, casts should be avoided. After my experience, the use of casts is soon or late source of errors (most of the time, difficult to detect and debug). Naturally, if they could not be avoided, then there is no choice. But they should be at least limited.

And as BS says:

Quote
...casts really are mostly avoidable in modern C++.

Michael

Offline yop

  • Regular
  • ***
  • Posts: 387
Re: cast and static cast
« Reply #13 on: December 11, 2005, 12:22:27 am »
Since you've brought this topic up let me ask one more thing. How do you handle buffers that the type of them depends on some given data? Say you have a transmition line and you get an array of bytes of a given size and you know that the first x number of bytes will be a general descriptive "header" structure that will describe what kind of data are following. Do you cast? (you'll have to reinterpret the pointer to the first byte to a pointer to a "header" struct and depending on the contents cast the last+1 byte of the header to an appropriate struct) Or do you let's say memcpy from the buffer to a new object of every needed struct? Or is there another way?
BTW I haven't yet figured out why to prefer one way or the other though I use the second one to keep the buffer intact
Life would be so much easier if we could just look at the source code.

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: cast and static cast
« Reply #14 on: December 11, 2005, 01:30:55 am »
Interesting, but not-easy to answer questions :).

Since you've brought this topic up let me ask one more thing. How do you handle buffers that the type of them depends on some given data? Say you have a transmition line and you get an array of bytes of a given size and you know that the first x number of bytes will be a general descriptive "header" structure that will describe what kind of data are following. Do you cast? (you'll have to reinterpret the pointer to the first byte to a pointer to a "header" struct and depending on the contents cast the last+1 byte of the header to an appropriate struct)

I would say, yes, I would probably cast. Cast, because, I know of which type the x number of bytes is. Anyway, this could be a problem if the code is not sufficiently documented and robust. For example, if I change the format of the stream, then I should change the parsing too. But what will happen, if I have forgotten some bytes?

This remeber me, when I played with an MPEG-4 visual bitstream parser. In such a bitstream, the different elements are represent using specific patterns (start code, length of the element, etc.) and are byte-aligned (theoretically at least). To parse the stream I simply read each element into a char array big enough to hold it (the interesting is that elements are represented using how much bits is required and not one more :)). If the element was a number, I casted it, e.g., to an int.

This article (http://www.codeproject.com/audio/MPEGAudioInfo.asp) about the structure of the MPEG audio frame header could be of some interest (even if I find it too M$ style).

Or do you let's say memcpy from the buffer to a new object of every needed struct? Or is there another way?

Not sure that there is another way. But may be one of my colleagues could have used something different/better. I will inquire :).

BTW I haven't yet figured out why to prefer one way or the other though I use the second one to keep the buffer intact

I think that to chose one way or another mostly depend on the application specifications and somehow on personal preferences.

Michael