803

I've heard that the static_cast function should be preferred to C-style or simple function-style casting. Is this true? Why?

Sisir
  • 4,584
  • 4
  • 26
  • 37
Tommy Herbert
  • 20,407
  • 14
  • 52
  • 57
  • 43
    Objection your honour, [asked and answered](http://stackoverflow.com/questions/28002/regular-cast-vs-staticcast-vs-dynamiccast). – Graeme Perrow Sep 19 '08 at 16:36
  • 30
    I disagree, this other question was about describing the differences between casts introduces in C++. This question is about the real usefulness of static_cast, which is slightly different. – Vincent Robert Sep 19 '08 at 16:40
  • 2
    We could certainly merge the two questions, but what we'd need to preserve from this thread is the advantage of using functions over C-style casting, which is currently only mentioned in a one-line answer in the other thread, with no votes. – Tommy Herbert Sep 20 '08 at 08:26
  • Up voting because that link still provides useful information. – Pete Aug 14 '09 at 17:45
  • 6
    This question is about "built-in" types, like int, whereas that question is about class types. That seems like a significant enough difference to merit a separate explanation. –  Apr 19 '11 at 21:21
  • 13
    static_cast is actually an operator, not a function. – ThomasMcLeod Feb 25 '13 at 13:47
  • 1
    @ThomasMcLeod Operators are a special type of function (at least that is what I thought) – DarthRubik Nov 26 '16 at 20:33
  • 2
    @DarthRubik, actually function calls are a type of operator. https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B – ThomasMcLeod Nov 28 '16 at 17:50
  • @user153275 well the title is about primitive types, but the question throws it away. And so do the answers. I am unconvinced to change my ways. Pretty sure `int x = (int)myfloat;` is gonna be just fine and do what I expect it to. – Josh C Sep 16 '19 at 18:15

9 Answers9

733

The main reason is that classic C casts make no distinction between what we call static_cast<>(), reinterpret_cast<>(), const_cast<>(), and dynamic_cast<>(). These four things are completely different.

A static_cast<>() is usually safe. There is a valid conversion in the language, or an appropriate constructor that makes it possible. The only time it's a bit risky is when you cast down to an inherited class; you must make sure that the object is actually the descendant that you claim it is, by means external to the language (like a flag in the object). A dynamic_cast<>() is safe as long as the result is checked (pointer) or a possible exception is taken into account (reference).

A reinterpret_cast<>() (or a const_cast<>()) on the other hand is always dangerous. You tell the compiler: "trust me: I know this doesn't look like a foo (this looks as if it isn't mutable), but it is".

The first problem is that it's almost impossible to tell which one will occur in a C-style cast without looking at large and disperse pieces of code and knowing all the rules.

Let's assume these:

class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

Now, these two are compiled the same way:

CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

However, let's see this almost identical code:

CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reinterpret_cast<>
                                                  // and it's wrong!!!

As you can see, there is no easy way to distinguish between the two situations without knowing a lot about all the classes involved.

The second problem is that the C-style casts are too hard to locate. In complex expressions it can be very hard to see C-style casts. It is virtually impossible to write an automated tool that needs to locate C-style casts (for example a search tool) without a full blown C++ compiler front-end. On the other hand, it's easy to search for "static_cast<" or "reinterpret_cast<".

pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is 
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

That means that, not only are C-style casts more dangerous, but it's a lot harder to find them all to make sure that they are correct.

Jarvis
  • 8,494
  • 3
  • 27
  • 58
Euro Micelli
  • 33,285
  • 8
  • 51
  • 70
  • 36
    You shouldn't use `static_cast` for casting down an inheritance hierarchy, but rather `dynamic_cast`. That will return either the null pointer or a valid pointer. – David Thornley Jan 20 '10 at 20:18
  • 49
    @David Thornley: I agree, usually. I think I indicated the caveats to using `static_cast` in that situation. `dynamic_cast` might be safer, but it's not always the best option. Sometimes you do *know* that a pointer points to a given subtype, by means opaque to the compiler, and a `static_cast` is faster. In at least some environments, `dynamic_cast` requires optional compiler support and runtime cost (enabling RTTI), and you might not want to enable it just for a couple of checks you can do yourself. C++'s RTTI is only one possible solution to the problem. – Euro Micelli Jan 20 '10 at 21:02
  • 21
    Your claim about C casts is false. All C casts are value conversions, roughly comparable to C++ `static_cast`. The C equivalent of `reinterpret_cast` is `*(destination_type *)&`, i.e. taking the address of the object, casting that address to a pointer to a different type, and then dereferencing. Except in the case of character types or certain struct types for which C defines the behavior of this construct, it generally results in undefined behavior in C. – R.. GitHub STOP HELPING ICE Feb 04 '12 at 05:56
  • 13
    Your fine answer addresses the body of the post. I was looking for an answer to the title "why use static_cast(x) instead of (int)x". That is, for type `int` (and `int` alone), why use `static_cast` vs. `(int)` as the only benefit seems to be with class variables and pointers. Request that you elaborate on this. – chux - Reinstate Monica Dec 15 '13 at 02:15
  • 43
    @chux, for `int` `dynamic_cast` doesn't apply, but all the other reasons stand. For example: let's say `v` is a function parameter declared as `float`, then `(int)v` is `static_cast(v)`. But if you change the parameter to `float*`, `(int)v` quietly becomes `reinterpret_cast(v)` while `static_cast(v)` is illegal and correctly caught by the compiler. – Euro Micelli Dec 19 '13 at 12:50
  • 1
    @EuroMicelli: I was bitten once by the situation you described. I cast a `double*` to `int` when I believed it to be `double`. It took me half a day of debugging, and since then, I avoid C-style casts at all cost. – Siyuan Ren May 10 '14 at 09:22
  • All of your examples are for classes and do an extremely good job of explaining why coders should absolutely use c++ cast operators. The issue I have is what do you do when you are dealing with a pod type like an int* to void* or void* to int*? In this situation do I use c-casts or c++ cast operators? I might end up adding this as a question in a different post. Not sure this belongs here. – Zachary Kraus Aug 27 '14 at 21:39
  • 7
    While it is not clear whether the question is supposed to be about C++-style casts in general or about arithmetic casts in particular, it is strange to see that the question uses what appears to be an arithmetic cast as an example, while the accepted answer completely ignores arithmetic casts and focuses exclusively on hierarchical pointer casts. (???) – AnT stands with Russia Oct 09 '14 at 02:27
  • One can actually argue that C++-style casts should be reserved for hierarchical pointer casts and various hack-casts, while classic C-style casts should be used for arithmetic casts. This would provide a clear distinction between these two (or three) rather different worlds of casts. On other words, when you are performing an arithmetic cast to `int` specifically, `(int) x` is actually the way to go, not `static_cast(x)`. – AnT stands with Russia Oct 09 '14 at 02:29
  • 1
    @AndreyT There is a difference between a C style cast and a `static_cast`... namely the [`const` part](http://stackoverflow.com/a/22999708/256138) (if we're talking about arithmetic casts), which in C is not that relevant but in C++ is enforced by the compiler a lot more... And can lead to undefined behaviour if you're not careful. – rubenvb Oct 09 '14 at 07:55
  • 2
    @AndreyT Technically you may be right. However, using C++ style casts adds compiler detection of cases where the programmer accidentally uses the wrong cast (e.g. `static_cast<>` was used, but `reinterpret_cast<>` is required). There's no real reason to pass up on that. And no, that includes cast to `(int)`, because you don't want the compiler to silently apply `reinterpret_cast` after you refactored some code). – sehe Oct 09 '14 at 07:57
  • 2
    @rubenvb: I don't understand what you are talking about. You must be confusing something. The matter of `const` does not come into play in arithmetic casts at all. The matter of `const` applies to pointer/reference casts only, which are not arithmetic. So, what point you are trying to make by mentioning `const` here and how it is related to what I said above is not clear to me. – AnT stands with Russia Oct 09 '14 at 15:03
  • 3
    @sehe: If the refactor is so major that it can turn an arithmetic cast into a reinterpret cast, then it will require a meticulous code review anyway, which will involve a lot more than detection and correction of such casts (assuming there's even a credible use case). – AnT stands with Russia Oct 09 '14 at 15:10
  • 2
    The effect of the additional piece of mind provided by `static_cast` in such cases is insignificant in my opinion, compared to the positive effect on the code readability provided by more elegant arithmetic casts and visual separation of arithmetic casts from hierarchical casts/hack-casts. I believe that the latter effect is significantly more valuable. So I stick with C-style casts for arithmetic conversions: the reward far far far outweighs the risk. – AnT stands with Russia Oct 09 '14 at 15:10
  • 3
    @AndreyT and the point is that meticulous code review can easily miss these things, exactly because they lack verbosity - the intent is not unambiguously stated. That's gonna lead to error. – sehe Oct 09 '14 at 15:14
  • @sehe: Oh, when the refactor is so drastic, a meticulous code review can miss a lot of things, among which this specific matter is not a big factor at all. Returning to the topic: in other words, even though they wanted to separate different kind of casts, they did not go far enough. `static_cast` is still too crowded. I require a dedicated cast for for arithmetic conversions. And I require it so badly that I will accept the risk of using a C-style cast for arithmetic conversions just to have my arithmetic casts look differently. – AnT stands with Russia Oct 09 '14 at 15:14
  • 2
    @AndreyT Nothing stops you from doing something like `integer_cast<>`, that does whatever you need it to do (I think there might be something in Boost Integer for this). Similar things may already exist (with specialized libs like [SafeInt](http://msdn.microsoft.com/en-us/library/dd570023.aspx)) – sehe Oct 09 '14 at 15:16
  • `you must make sure that the object is a actually the descendant that you claim it is, by means external to the language (like a flag in the object).` I don't agree (aside from the fact that a member in an object is not "external to the language"): if the program is properly designed, it is perfectly possible to know that the object is the right type, and flagging it wastes space. Just be sure you know what your instances are if you're `static_cast`ing, and be sure to `assert()` on the equivalent `dynamic_cast` when running debug builds. – underscore_d May 12 '17 at 23:30
  • @jterm What? There's nothing unsafe, if the instance that is cast to "child" _is_ a child and _does_ have those members, which a good programmer will know. (And, ideally, `assert( dynamic_cast ... )` in debug builds) – underscore_d May 12 '17 at 23:30
  • @underscore_d , by "external to the language" I mean that the language does not enforce the meaning of any such flag (the compiler doesn't know what it means, and can't check it). "I know what I'm doing" as you point out is perfectly valid, of course, and might save you from using a flag depending on the program. That, is also "external to the language" :-). – Euro Micelli May 13 '17 at 00:24
  • "_no distinction between what we call static_cast<>(), reinterpret_cast<>(), const_cast<>(), and dynamic_cast<>_" the "distinction" is that there is no such thing as a `dynamic_cast<>` done through C style cast or functional style cast syntax – curiousguy May 28 '18 at 02:10
  • 2
    `dynamic_cast<>()` isn't related to c style cast. – Amos Jun 21 '18 at 07:26
  • Another situation where `static_cast` can be risky is that `static_cast` allows you to convert any pointer type to `void*` and `void*` to any pointer type, which would allow you to for example cast `char*` to `void*` and then to`int*`. – Donald Duck Jul 11 '18 at 03:08
  • It's a good practice to use a macro-defined keyword to locate casts across c files. – mitghi Aug 09 '18 at 13:06
  • _"a `const_cast<>()` [...] is always dangerous"_ - not so, only if used to _remove_ `const` or `volatile`. `const_cast(t)` is always safe, and `const_cast(t)` is safe provided `t` is not volatile. – Eric Oct 07 '19 at 07:28
  • @DonaldDuck "_which would allow you to for example cast_" If you are dealing with a `void*`, and you believe it came from a `T*` but aren't really sure, there is no solution. No cast syntax will help as it's fundamentally a design issue. – curiousguy Nov 02 '19 at 23:50
  • *Way* better advice than what I learned from which was just blindly calling things "evil" instead of explaining their uses and their pitfalls. +10 even though I can only give +1 – The_Sympathizer Jun 05 '20 at 05:10
  • This is a great answer, but failed to address the "function-style cast" part of the question (no one else did either). "function-style casts" are not really casts at all, but declaration of anonymous temporaries of the desired type. They rely on the type being constructible from the argument and are completely type-safe. There is no reason not to use them. – jwm Nov 18 '22 at 01:16
126

One pragmatic tip: you can search easily for the static_cast keyword in your source code if you plan to tidy up the project.

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
Karl
  • 3,170
  • 1
  • 21
  • 28
  • 7
    you can search using the brackets also though such as "(int)" but good answer and valid reason to use C++ style casting. – Mike Jan 07 '14 at 11:28
  • 8
    @Mike that will find false positives - a function declaration with a single `int` parameter. – Nathan Osman Sep 13 '16 at 05:22
  • 1
    This can give false negatives: if you're searching a codebase where you're not the only author, you won't find C-style casts others might have introduced for some reasons. – Ruslan Jun 09 '17 at 06:46
  • 15
    How would doing this help to tidy up the project ? – Bilow Oct 10 '17 at 18:40
  • You would not search for static_cast, because it is most likely the correct one. You want to filter out static_cast, while you search for reinterpret_cast, const_cast, and maybe even dynamic_cast, as those would indicate places that can be redesigned. C-cast mixes in all together and doesn't give you the reason for casting. – Dragan May 18 '20 at 13:58
119

In short:

  1. static_cast<>() gives you a compile time checking ability, C-Style cast doesn't.
  2. static_cast<>() can be spotted easily anywhere inside a C++ source code; in contrast, C_Style cast is harder to spot.
  3. Intentions are conveyed much better using C++ casts.

More Explanation:

The static cast performs conversions between compatible types. It is similar to the C-style cast, but is more restrictive. For example, the C-style cast would allow an integer pointer to point to a char.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Since this results in a 4-byte pointer pointing to 1 byte of allocated memory, writing to this pointer will either cause a run-time error or will overwrite some adjacent memory.

*p = 5; // run-time error: stack corruption

In contrast to the C-style cast, the static cast will allow the compiler to check that the pointer and pointee data types are compatible, which allows the programmer to catch this incorrect pointer assignment during compilation.

int *q = static_cast<int*>(&c); // compile-time error

Read more on:
What is the difference between static_cast<> and C style casting
and
Regular cast vs. static_cast vs. dynamic_cast

Community
  • 1
  • 1
Hossein
  • 24,202
  • 35
  • 119
  • 224
  • 26
    I disagree that `static_cast<>()` is more readable. I mean, *sometimes* it is, but most of the time — especially on basic integer types — it's just horribly and unnecessarily verbose. For example: This is a function that swaps the bytes of a 32-bit word. It would be nearly impossible to read using `static_cast()` casts, but is quite easy to understand using `(uint##)` casts. **Picture of code:** http://imgur.com/NoHbGve – Todd Lehman Aug 04 '15 at 22:17
  • 4
    @ToddLehman: Thank you, but I didnt say `always` either. (but most of the times yes) There sure are cases where the c style cast is way more readable. Thats one of the reasons c style casting is still live and kicking in c++ imho. :) By the way that was a very nice example – Hossein May 23 '16 at 10:06
  • 13
    @ToddLehman code in that image uses two casts chained (`(uint32_t)(uint8_t)`) to achieve that bytes besides lowest are reset. For that there is bitwise and (`0xFF &`). Usage of casts is obfuscating the intention. – Öö Tiib Aug 20 '18 at 13:02
  • 1
    static_cast is not unreadable, it's just verbose. It is also unambiguous, in terms of the compile-time behavior. The argument for readability over clarity can only win by convincing us that the reader will find more bugs in ambiguous-but-readable code than a compiler will find when it is compiling semantically unambiguous code. It cannot be won just by claiming that "*this* is more readable than *that*" -- but if that were indeed the only point of debate, I think static_cast is in the lead, particularly since unambiguity is itself a property of readability. – John Doggett Dec 27 '21 at 19:42
  • I would have preferred to find this as the accepted answer, since it directly confronts the controversy: the use of static_cast<> for primitive types like `int` – John Doggett Dec 27 '21 at 19:45
  • 2
    @ToddLehman Your code is an exact example of why to avoid casts in the first place. (see alternative implementation without casts http://fxr.watson.org/fxr/source/lib/libkern/bswap32.c?v=NETBSD3) – j123b567 Mar 16 '22 at 10:45
  • @j123b567 — Ya, potentially that `bswap32` implementation is less efficient, because it involves 32-bit constants rather than pure register shifts, but I suppose modern compilers will optimize it all down to the same thing anyway. Nice example, btw. Thanks. – Todd Lehman Mar 16 '22 at 16:57
  • @ToddLehman fun fact, most moder compilers will compile it to one instruction (https://godbolt.org/z/K4P8Eo3he) The code with casts is the worst compilable acros compilers and e.g ICC and MSVC are not able to optimize it at all (https://godbolt.org/z/sh66TsK9E) – j123b567 Mar 17 '22 at 19:20
31

The question is bigger than just using whether static_cast<> or C-style casting because there are different things that happen when using C-style casts. The C++ casting operators are intended to make those different operations more explicit.

On the surface static_cast<> and C-style casts appear to be the same thing, for example when casting one value to another:

int i;
double d = (double)i;                  //C-style cast
double d2 = static_cast<double>( i );  //C++ cast

Both of those cast the integer value to a double. However when working with pointers things get more complicated. Some examples:

class A {};
class B : public A {};

A* a = new B;
B* b = (B*)a;                                  //(1) what is this supposed to do?

char* c = (char*)new int( 5 );                 //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

In this example (1) may be OK because the object pointed to by A is really an instance of B. But what if you don't know at that point in code what a actually points to?

(2) may be perfectly legal (you only want to look at one byte of the integer), but it could also be a mistake in which case an error would be nice, like (3).

The C++ casting operators are intended to expose these issues in the code by providing compile-time or run-time errors when possible.

So, for strict "value casting" you can use static_cast<>. If you want run-time polymorphic casting of pointers use dynamic_cast<>. If you really want to forget about types, you can use reintrepret_cast<>. And to just throw const out the window there is const_cast<>.

They just make the code more explicit so that it looks like you know what you were doing.

cassepipe
  • 371
  • 6
  • 16
Dusty Campbell
  • 3,146
  • 31
  • 34
28

static_cast means that you can't accidentally const_cast or reinterpret_cast, which is a good thing.

cbuchart
  • 10,847
  • 9
  • 53
  • 93
DrPizza
  • 17,882
  • 7
  • 41
  • 53
  • 4
    Additional (though rather minor) advantages over the C style cast is that it stands out more (doing something potentially bad should look ugly) and it's more grep-able. – Michael Burr Sep 19 '08 at 16:52
  • 4
    grep-ability is always a plus, in my book. – Branan Sep 22 '08 at 19:15
8
  1. Allows casts to be found easily in your code using grep or similar tools.
  2. Makes it explicit what kind of cast you are doing, and engaging the compiler's help in enforcing it. If you only want to cast away const-ness, then you can use const_cast, which will not allow you to do other types of conversions.
  3. Casts are inherently ugly -- you as a programmer are overruling how the compiler would ordinarily treat your code. You are saying to the compiler, "I know better than you." That being the case, it makes sense that performing a cast should be a moderately painful thing to do, and that they should stick out in your code, since they are a likely source of problems.

See Effective C++ Introduction

JohnMcG
  • 8,709
  • 6
  • 42
  • 49
6

It's about how much type-safety you want to impose.

When you write (bar) foo (which is equivalent to reinterpret_cast<bar> foo if you haven't provided a type conversion operator) you are telling the compiler to ignore type safety, and just do as it's told.

When you write static_cast<bar> foo you are asking the compiler to at least check that the type conversion makes sense and, for integral types, to insert some conversion code.


EDIT 2014-02-26

I wrote this answer more than 5 years ago, and I got it wrong. (See comments.) But it still gets upvotes!

Pitarou
  • 2,211
  • 18
  • 25
  • 9
    (bar)foo is not equivalent to reinterpret_cast(foo). The rules for "(TYPE) expr" are that it will choose the appropriate C++ style cast to use, which may include reinterpret_cast. – Richard Corden Sep 19 '08 at 17:43
  • 1
    Good point. Euro Micelli gave the definitive answer for this question. – Pitarou Sep 20 '08 at 17:03
  • 1
    Also, it is `static_cast(foo)`, with parentheses. Same for `reinterpret_cast(foo)`. – L. F. Jul 25 '19 at 01:58
6

C Style casts are easy to miss in a block of code. C++ style casts are not only better practice; they offer a much greater degree of flexibility.

reinterpret_cast allows integral to pointer type conversions, however can be unsafe if misused.

static_cast offers good conversion for numeric types e.g. from as enums to ints or ints to floats or any data types you are confident of type. It does not perform any run time checks.

dynamic_cast on the other hand will perform these checks flagging any ambiguous assignments or conversions. It only works on pointers and references and incurs an overhead.

There are a couple of others but these are the main ones you will come across.

Konrad
  • 39,751
  • 32
  • 78
  • 114
5

static_cast, aside from manipulating pointers to classes, can also be used to perform conversions explicitly defined in classes, as well as to perform standard conversions between fundamental types:

double d = 3.14159265;
int    i = static_cast<int>(d);
prakash
  • 58,901
  • 25
  • 93
  • 115
  • 7
    Why would anyone write `static_cast(d)`, though, when `(int)d` is so much more concise and readable? (I mean in the case of basic types, not object pointers.) – Todd Lehman Aug 04 '15 at 22:21
  • @gd1 — Why would anyone put consistency above readability? (actually half serious) – Todd Lehman Jan 13 '16 at 19:35
  • 2
    @ToddLehman : Me, considering that making an exception for certain types just because they're somehow special to you does not make any sense to me, and I also disagree on your very notion of readability. Shorter does not mean more readable, as I see from the image you posted in another comment. – gd1 Jan 13 '16 at 19:45
  • 2
    static_cast is a clear and conscious decision to make a very particular kind of conversion. It therefore adds to clarity of intention. It's also very handy as a marker to search source files for conversions in a code review, bug or upgrading exercise. – Persixty Jan 18 '16 at 10:19
  • 1
    @ToddLehman counterpoint: Why would anyone write `(int)d` when `int{d}` is so much more readable? Constructor, or function-like if you have `()`, syntax isn't nearly so fast to devolve into a nightmarish maze of parentheses in complex expressions. In this case, it'd be `int i{d}` instead of `int i = (int)d`. Far better IMO. That said, when I just need a temporary in an expression, I use `static_cast` and have never used constructor casts, I don't think. I only use `(C)casts` when hurriedly writing debug `cout`s... – underscore_d May 12 '17 at 23:39