• Advertisement
Sign in to follow this  

(split thread) c-style casts

This topic is 764 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I honestly can't understand why anybody recommends them over C-style casting.

Then you should consider that they were invented because people got tired of shooting themselves in the foot by “over-casting”.

 

 

L. Spiro

Share this post


Link to post
Share on other sites
Advertisement
Does anyone know of an example where C-style cast causes a problem with non-pointer/non-reference types? All of the intentional problems I've tried to cause result in compile-time errors. Edited by Nypyren

Share this post


Link to post
Share on other sites

 

I honestly can't understand why anybody recommends them over C-style casting.

Then you should consider that they were invented because people got tired of shooting themselves in the foot by “over-casting”.

 

 

L. Spiro

 

static_cast<T> == (T)
reinterpret_cast<T*> == (T*)
const_cast<const T*> == (T*)

I've not once run into a bug caused by C style casting that would not also have been caused by one of those C++ casts. So instead of just shooting yourself in the foot, you should get three guns to choose from?
 

 


It was a sobering realisation that even floating point limits can be easily exceeded by multiplying seemingly small quantities, especially since they are used in the oft-mentioned "critical loops", "engine cores," "numeric libraries." I started appreciating things like media compression artifacts, 3D graphics clipping, statistical / mechanical errors...

Most of the time in games you're working with values -1.0 <= x <= 1, and multiplying values in that range together. This prevents the issue you noticed from happening because the result will always be in that same range. The higher precision of double might make some difference in some corner case, but generally it's not necessary. I personally have had good results in software rasterizing with a fixed point type with 15 bits of precision (8 bits less than IEEE single precision float).
 

 


I just had this naive impression that ieee float dealt with the int-overflowing-multiply-by-10 by incrementing an exponent such that it could handle much larger values; e.g. 10 to the 10 "felt" possible with little error. On the fraction part, I "knew" shifting the decimal point would favour double but a clear "error" in the fraction part when doing float(double) was a shock.

floating point exponents are applied to a base of 2, not 10, unless you specify them as decimal.
IIRC 2^127x(1-FLT_EPSILON) is the largest value possible in a float, but you'd need 128 bits to represent all numbers in this range accurately.

Edited by nfries88

Share this post


Link to post
Share on other sites

static_cast<T*> == (T)
reinterpret_cast<T*> == (T*)
const_cast<T*> == (const T*)

I've not once run into a bug caused by C style casting that would not also have been caused by one of those C++ casts. So instead of just shooting yourself in the foot, you should get three guns to choose from?

Just a minor complaint about your usage of const cast - const_cast<const T*> is wrong, the way you use it is actually const_cast<T*>, and thus the equivalent c-style cast is (T*) - thats one of the reasons why C-style casts can be considered bad, because you might just cast a const modifier away where you didn't expect to.

Edited by Juliean

Share this post


Link to post
Share on other sites

I've heard of a studio in the past few years ban C++ casts altogether due to bugs/weirdness in generated assembly.

 

As for "getting the wrong type of cast" with a C-style cast, you can look at the code and easily find the different between reinterpret and static cast by noticing if the cast is casting a pointer type or not. As for const cast, well that only holds merit if your code base believes in using const in the first place. I think the argument that made the most sense to me is C++ casts are way easier to parse compared to C-style casts, which makes code pre-processing potentially easier.

Share this post


Link to post
Share on other sites

 


static_cast<T*> == (T)
reinterpret_cast<T*> == (T*)
const_cast<T*> == (const T*)

I've not once run into a bug caused by C style casting that would not also have been caused by one of those C++ casts. So instead of just shooting yourself in the foot, you should get three guns to choose from?

Just a minor complaint about your usage of const cast - const_cast<const T*> is wrong, the way you use it is actually const_cast<T*>, and thus the equivalent c-style cast is (T*) - thats one of the reasons why C-style casts can be considered bad, because you might just cast a const modifier away where you didn't expect to.

 

You're right, of course, I was typing that message in a hurry because I was on my way out the door.


I've heard of a studio in the past few years ban C++ casts altogether due to bugs/weirdness in generated assembly.

I can believe weirdness, but not bugs, unless it was some special-purpose compiler they were using (IE one for some specific console).


As for const cast, well that only holds merit if your code base believes in using const in the first place.

I think const serves a valid purpose in describing the usage of function arguments. Const allows optimization in some handful of cases, too. I'm not sure it's valid for much else. And really the using of const_cast generally means that the function argument you're casting should not have been declared const in the first place, it means you are breaking your promise of non-modification.


I think the argument that made the most sense to me is C++ casts are way easier to parse compared to C-style casts, which makes code pre-processing potentially easier.

So we should never use C-style casts... to shave a few microseconds off compile time?

Share this post


Link to post
Share on other sites
edit: Really, multiquote? Yes, /quote tags are a thing...
 

As for "getting the wrong type of cast" with a C-style cast, you can look at the code and easily find the different between reinterpret and static cast by noticing if the cast is casting a pointer type or not.


 
That's not quite true. Some pointer types can be (and are) used with static_cast. You can use static_cast to convert a pointer to a base class to a pointer to a derived class, but this isn't considered especially safe. It's more accurate to think of static_cast as a way of telling the compiler to cast to the specified type in such a way that the compiler listens to the type system, while reinterpret_cast just ignores the type system and does what you ask (but only on pointer types).
 

I can believe weirdness, but not bugs, unless it was some special-purpose compiler they were using (IE one for some specific console).


 
Yep. A lot of studios avoided templates (and by extension huge swathes of the standard library) for similar reasons.

 

I think const serves a valid purpose in describing the usage of function arguments. Const allows optimization in some handful of cases, too. I'm not sure it's valid for much else.


It's useful for minimizing side-effects. It's harder to accidentally change something if the compiler won't let you. Some have argued that variables should be const by default, and mutability should be explicitly declared. Passing by const-reference ensures that you don't add side effects by accident where you don't need them in addition to allowing optimization.
 

So we should never use C-style casts... to shave a few microseconds off compile time?


 

 
Parsing is not only done by compilers. ;)
 
1. Suppose I wanted to check for all the places where I cast a void* to a Foo* - as opposed to casting to a Foo* from its base class, Bar. Then I'd open up my search function and search for "reinterpret_cast<Foo*>" and get what I wanted.
2. C++ casts stand out more in the code - useful because explicitly calling out casting can make certain types of bugs more obvious - off the top of my head, float -> integer conversions and signed -> unsigned conversions are good examples of that.
3. C++ casts signify intent. If I'm using reinterpret_cast, then I'm telling other programmers (not just the compiler) that my intent is to reinterpret, whereas if I'm using static_cast, I'm telling them that my intent is to do an actual type conversion. Edited by Oberon_Command

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement