29

So, what do you use?

int anInt = (int)aFloat;

or

int anInt = static_cast<int>(aFloat);
// and its brethren

And, more importantly, why?

0

9 Answers 9

61

First, understand that those lines are not equivalent.

int* anInt = (int*)aFloat; // is equivalent to

int* anInt = reinterpret_cast<int*>(aFloat); 

What is happening here is that the programmer is asking the compiler to do whatever it can to make the cast.

The difference is important because using static_cast will only ask for a base type that is "safe" to convert to, where reinterpret_cast will convert to anything, possibly by just mapping the wanted memory layout over the memory of the given object.

So, as the "filter" is not the same, using a specific cast is more clear and safe than using the C cast. If you rely on the compiler (or runtime implementation if you use dynamic_cast) to tell you where you did something wrong, by avoid using C cast and reinterepret_cast.

Now that this is more clear, there is another thing: static_cast, reinterpret_cast, const_cast and dynamic_cast are easier to search for.

And the ultimate point: they are ugly. That's wanted. Potentially buggy code, code smells, obvious "tricks" that might generate bugs, are easier to track when it's associated with ugly look. Bad code should be ugly.

That's "by design". And that allows the developer to know where he could have done things better (by totally avoiding casts, if not really needed) and where it's fine but it's "documented" in the code by "marking" it as ugly.

A secondary reason for introducing the new-style cast was that C-style casts are very hard to spot in a program. For example, you can't conveniently search for casts using an ordinary editor or word processor. This near-invisibility of C-style casts is especially unfortunate because they are so potentially damaging. An ugly operation should have an ugly syntactic form. That observation was part of the reason for choosing the syntax for the new-style casts. A further reason was for the new-style casts to match the template notation, so that programmers can write their own casts, especially run-time checked casts.

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++.

Source: Bjarne Stroustrup (C++ creator)

3
  • 8
    I would downvote this if I had a few more points, but unfortunately I cannot. c-style casts are NOT equivalent to reinterpret_cast. Consider reinterpret_cast<int>(double);. It is entirely possible to cast a double to an int with a c-style cast, but it is not possible to do it with reinterpret_cast. I see Timbo already pointed this out to you, and you said you would fix it, but four years later it remains incorrect. I would still downvote you if that were fixed though, as there are perfectly valid reasons to need to use a cast. Here's a better answer: stackoverflow.com/a/332086/3878168
    – Yay295
    Nov 3, 2015 at 17:33
  • 1
    casts really are mostly avoidable in modern C++ While strictly true, it's often not achievable in practice, where you have to mix C and C++ (for example, even in 2021, lots of libraries for microcontroller and embeddded are written in C, like Arduino, FreeRTOS, ESP-IDF and many peripheral drivers for e.g. displays) Oct 28, 2021 at 12:32
  • Additinally, in cases like stackoverflow.com/a/35936719/1052284 ugly-casting is the 'cleanest' solution even in pure C++. Oct 28, 2021 at 12:46
41

C++ casts are more restrictive (so express your intent better and make code review easier, etc.). They're also much easier to search for, if you ever need to.

7
  • 13
    ... and they are more likely to do what you intend. ;-)
    – Macke
    Jun 27, 2011 at 11:51
  • 7
    And they are a lot more to type, giving you one more reason to just get your types correct without casts needed. Jun 27, 2011 at 12:05
  • 9
    And they are ugly as a feature, making obvious where in the code there might be points of improvement or special cases that might require documentation. - edit: wow I just discovered I answered this question too! XD
    – Klaim
    Jun 27, 2011 at 12:26
  • Now why would I want to search for them? Apr 12, 2015 at 14:03
  • @Deduplicator There are a lot of reasons you might want to know where casts are happening in a code-base. For example when hunting bugs which could be associated with casting (in particular when doing cross-platform development).
    – Klaim
    Apr 12, 2015 at 15:35
15

Option C: a "C++-style" cast, because it is indistinguishable from a construction:

int anInt = int(aFloat);

or even:

int anInt(aFloat);

That aside, other than these trivial cases with primitives, which are well understood, I prefer to use x_cast<>s over C-style casts. There are three reasons why:

  • They more narrowly define the operation the programmer was trying to perform.

  • They can perform actions that C-style casts cannot (especially in the case of dynamic_cast<>, which can cross-cast across branches of a multiple-inheritance chain).

  • They are ugly. They loudly declare that the programmer is working against the type system. In this case, it's a good thing.

2
  • It's really sad to see that the first correct and reasoned answer comes third, and has less than a third the votes of the accepted and wrong answer. Jan 12, 2021 at 22:44
  • I appreciate the vote of confidence. ;)
    – Kaz Dragon
    Jan 14, 2021 at 14:54
9

I have a few rules about C/C++-style casts:

  1. Dis-applying a const must always use a const_cast. For obvious reasons. Sadly, my rule about dis-applying a const causing the keyboard to reach up and break the programmer's finger was not approved.
  2. Any of the bit-manipulation-style shenanigans that programmers get up to when getting down to the metal should use reinterpret_cast. It's really the kind of cast that C doesn't have: pretend this integer's bits are actually a float's bits. This avoids unpleasantness like (int)(*(int*)(&floatVar)).
  3. If you type the words "dynamic_cast", stop and re-evaluate your polymorphic class hierarchy and design. Continue re-evaluating your class hierarchy's design until you can delete those words.
  4. Don't bother with static_cast.

The reasoning behind #4 is simply that it doesn't matter. The circumstances that don't fit into the other rules are either obvious or really low-level. A well-understood conversion of simple types like int-to-float should not need special syntax. And if you're down in the deep, ugly guts of something, well, you're down in the deep, ugly guts of something. There's no need to draw attention to the fact that "here there be dragons," since the teeth, claws, and fire pretty much gave it away already.

4
  • 2
    dynamic_cast is a perfectly valid tool. Rarely useful, I'll admit, but it's far from the Satan of things like global variables. However, primarily, I downvoted you because you didn't answer the question, which was about the use or not of C-style casts.
    – DeadMG
    Jun 27, 2011 at 18:25
  • 2
    @DeadMG: I did talk about C-style casts. The whole last paragraph justifies C-style casts in favor of static_cast. Jun 27, 2011 at 21:38
  • "Sadly, my rule about dis-applying a const causing the keyboard to reach up and break the programmer's finger was not approved." Technically it's actually legal for the compiler to make that happen. As is it legal for the compiler to make demons fly out of your nose.
    – Pharap
    Sep 18, 2019 at 15:49
  • @Pharap If it was constant to begin with, instead of only that view. And then only on execution of the code. Jan 12, 2021 at 22:46
7

If writing code in C use a C cast. If writing in C++ use a C++ cast.

Whilst most casting breaks proper type-safety, the C++ ones are more restrictive, and therefore you are slightly less type-unsafe than you would be with a C cast.

I can tolerate someone using (T*)NULL though to force an overload...

4

As the above posts note the C++ (static) cast is a bit safer in practice.

It might be smart to look up some more information about the different kinds of casting and their pro's and cons.

Just to have more of a background on why. .

http://en.wikipedia.org/wiki/Static_cast

http://en.wikipedia.org/wiki/Dynamic_cast

http://en.wikipedia.org/wiki/Reinterpret_cast

3

It really depends on which language I'm working with, since you know what they say: In Rome speak Roman. So if I'm programming in C, I try to use the C features to the max, but if I'm programming at C++ I go ahead and use C++ features to the max, even if some people don't like that approach because they say it makes the code "less portable", I say that I don't care, I'm in C++ and programming in C++, and I need a fully C++ compatible compiler to compile code, otherwise I would be working with something different in the first place.

1
  • It doesn't really work trying to use C++-style casts in C ;-)
    – user8709
    Mar 1, 2011 at 8:55
3

static_cast etc were invented because of problems with the C style casts when used in templates. If you're writing a template, or if you're code may later be converted to a template, it's a good idea to use C++-style casts. The reason is because the C++-style casts better express intent, so they will give the expected results in cases where C-style casts will do the wrong thing (given particular types as template parameters).

Other than that, I say use C++-style casts if you have a specific issue that needs them - dynamic_cast is the most common, but even that's probably not an every day thing.

Anything else, and a C style cast may be a bit less clutter and help readability, or maybe not depending on how familiar the reader is with that cast style these days. It's not really important in my view, mostly a personal preference thing, though don't be surprised if some people don't like the C style.

Final note - if you need so many casts that this is a big deal, you're probably doing something else wrong. There are exceptions to that in some cases, but most high level code shouldn't need many (if any) casts.

0

This is an old question, but nobody had said this yet:

C-style casts are only unsafe only when casting to pointers or references, especially when classes are involved.

In all other cases, C-style casts are fine, and (I believe) improve readability compared to static_cast.

(In this answer I use "C-style cast" as an umbrella term for both (T)x, T(x), and T{x}, even though they have slightly different behavior.).


When classes are involved, a C-style cast to a pointer or reference can do one of the three things: (which are tried in this order)

  1. Cast between a base class to a derived class (or back), which potentially changes the numerical value of the pointer when multiple inheritance is involved. (Like a static_cast.)

  2. Invoke a user-defined conversion operator. (Like a static_cast.)

  3. Perform a reinterpret_cast.

You really don't want 1 or 2 to accidentally turn into 3 (or vice versa), either because the class interface changed and you forgot to update the usage, or just because you made a mistake.

Even if we ignore 1 and 2, reinterpret_cast is inherently unsafe, so it's useful to make it more visible (by spelling it as a C++ cast).

Additionally, a C-style cast can implicitly add the treacherous const_cast to the conversions listed above, which is yet another reason to avoid it for pointers and references.


When casting to something that's not a pointer or a reference, a C-style cast behaves exactly like static_cast.

I see no reason to spell a / float(b) as a / static_cast<float>(b), since it doesn't add any extra safety.

The only argument in favor of using static_cast in this case is that it's easier to find in the code, but I never had a need to do that, not a single time.

But if you do need to find all casts for some reason, we now have tools like libclang, which let you do this relatively easily, regardless of the syntax you used.

3
  • float(b) is not the same as (float)b. float{b} is even more distinct
    – Caleth
    May 3 at 13:43
  • @Caleth float{...} is distinct, yes. But I'm not aware of any significant differences between float(...) and (float).... The only one I remember is that CTAD doesn't work with the latter. May 3 at 13:44
  • @HolyBlackCat That difference seems pretty accidental. May 3 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.