8.5 — Explicit type conversion (casting) and static_cast

In lesson 8.1 -- Implicit type conversion (coercion), we discussed that the compiler can implicitly convert a value from one data type to another through a system called implicit type conversion. When you want to numerically promote a value from one data type to a wider data type, using implicit type conversion is fine.

Many new C++ programmers try something like this:

Because 10 and 4 are both of type int, integer division is performed, and the expression evaluates to int value 2. This value then undergoes numeric conversion to double value 2.0 before being used to initialize variable d. Most likely, this isn’t what was intended.

In the case where you are using literal operands, replacing one or both of the integer literals with double literals will cause floating point division to happen instead:

But what if you are using variables instead of literals? Consider this case:

Because integer division is used here, variable d will end up with the value of 2.0. How do we tell the compiler that we want to use floating point division instead of integer division in this case? Literal suffixes can’t be used with variables. We need some way to convert one (or both) of the variable operands to a floating point type, so that floating point division will be used instead.

Fortunately, C++ comes with a number of different type casting operators (more commonly called casts) that can be used by the programmer to request that the compiler perform a type conversion. Because casts are explicit requests by the programmer, this form of type conversion is often called an explicit type conversion (as opposed to implicit type conversion, where the compiler performs a type conversion automatically).

Type casting

C++ supports 5 different types of casts: C-style casts, static casts, const casts, dynamic casts, and reinterpret casts. The latter four are sometimes referred to as named casts.

We’ll cover C-style casts and static casts in this lesson.

Related content

We discuss dynamic casts in lesson 18.10 -- Dynamic casting, after we’ve covered other prerequisite topics.

Const casts and reinterpret casts should generally be avoided because they are only useful in rare cases and can be harmful if used incorrectly.


Avoid const casts and reinterpret casts unless you have a very good reason to use them.

C-style casts

In standard C programming, casts are done via the () operator, with the name of the type to convert the value to placed inside the parenthesis. You may still see these used in code (or by programmers) that have been converted from C.

For example:

In the above program, we use a C-style cast to tell the compiler to convert x to a double. Because the left operand of operator/ now evaluates to a floating point value, the right operator will be converted to a floating point value as well, and the division will be done using floating point division instead of integer division!

C++ will also let you use a C-style cast with a more function-call like syntax:

This performs identically to the prior example, but has the benefit of parenthesizing the value being converted (making it easier to tell what is being converted).

Although a C-style cast appears to be a single cast, it can actually perform a variety of different conversions depending on context. This can include a static cast, a const cast or a reinterpret cast (the latter two of which we mentioned above you should avoid). As a result, C-style casts are at risk for being inadvertently misused and not producing the expected behavior, something which is easily avoidable by using the C++ casts instead.

Related content

If you’re curious, this article has more information on how C-style casts actually work.

Best practice

Avoid using C-style casts.


C++ introduces a casting operator called static_cast, which can be used to convert a value of one type to a value of another type.

You’ve previously seen static_cast used to convert a char into an int so that std::cout prints it as an integer instead of a char:

The static_cast operator takes an expression as input, and returns the evaluated value converted to the type specified inside the angled brackets. Static_cast is best used to convert one fundamental type into another.

The main advantage of static_cast is that it provides compile-time type checking, making it harder to make an inadvertent error. Static_cast is also (intentionally) less powerful than C-style casts, so you can’t inadvertently remove const or do other things you may not have intended to do.

Best practice

Favor static_cast when you need to convert a value from one type to another type.

Using static_cast to make narrowing conversions explicit

Compilers will often issue warnings when a potentially unsafe (narrowing) implicit type conversion is performed. For example, consider the following program:

Casting an int (2 or 4 bytes) to a char (1 byte) is potentially unsafe (as the compiler can’t tell whether the integer value will overflow the range of the char or not), and so the compiler will typically print a warning. If we used list initialization, the compiler would yield an error.

To get around this, we can use a static cast to explicitly convert our integer to a char:

When we do this, we’re explicitly telling the compiler that this conversion is intended, and we accept responsibility for the consequences (e.g. overflowing the range of a char if that happens). Since the output of this static_cast is of type char, the initialization of variable ch doesn’t generate any type mismatches, and hence no warnings or errors.

Here’s another example where the compiler will typically complain that converting a double to an int may result in loss of data:

To tell the compiler that we explicitly mean to do this:

Quiz time

Question #1

What’s the difference between implicit and explicit type conversion?

Show Solution

8.6 -- Typedefs and type aliases
8.4 -- Arithmetic conversions

143 comments to 8.5 — Explicit type conversion (casting) and static_cast

  • James C

    Capital 'S' on static_cast in this sentence:

    "Static_cast is best used to convert one fundamental type into another."

  • Forhad Rahman

    This prints A8_i, what does this mean? Is this the reason I have to convert this myArray into 'int' using static_cast? Because 'A8_i' is not a valid datatype... or A8_i doesn't make any sense in type... ?

    • Alex

      A8_i is your compiler's way of telling you that this is an array of 8 integer. The return value of typeid().name() is compiler dependent, so other compilers may produce something different.

      > Is this the reason I have to convert this myArray into 'int' using static_cast?

      I don't know what this means.

      • Forhad Rahman

        > A8_i is your compiler's way of telling you that this is an array of 8 integer.
        - So... myArray is ultimately an integer datatype?

        Ok, I thought so the conversion question won't be understandable, my bad. In for-each loops chapter, you showed this code at the beginning -


        - What is the purpose of this?
        numStudents will hold 5 anyway. And it's already an integer type. Then why are you converting numStudents into 'int' again using static_cast anyway?

        Note: This C++ is blowing my mind up so I am messing with everything. Don't mind for such stupid questions :]

        • nascardriver

          This cast is not needed, because `std::size()` is a `constexpr` function, I've removed it from the example.

          `std::size()` returns a `std::size_t`, which is some unsigned integer type. Converting from `unsigned` to `signed` in list-initialization is not allowed and would cause a compiler error. "Would", because this conversion is allowed for `constexpr` values (Because the compiler can figure out if the conversion succeeds).

          • Forhad Rahman

            Okay. But what about this program? Can't make any sense what's going on here.

            If I use 'int' instead of 'size_t', the compiler complains that - error: conversion to 'std::array<const char*, 5>::size_type' {aka 'long long unsigned int'} from 'int' may change the sign of the result. [Using 'unsigned int' also works fine, like 'size_t']

            Why this happens? size_t is ultimately an unsigned int(or alias type something I read earlier), isn't it? Well, I am not using any negative calculation using 'int' here but it's still complaining. One said me that, holding both positive and negative number(in signed type) requires more resource than unsigned, is it true?

            So, what data type is studentList? Why it's only working with std::size_t/unsigned int? Not with int? [using vector type instead of array in studentList throws the same complain]

            I am using Code Blocks, the latest one I guess. Warnings are treating as error.

            • nascardriver

              `std::size_t` is some unsigned integer type, usually 64 bits wide (eg. `unsigned long`).

              > I am not using any negative calculation
              The compiler doesn't know the values of your variables unless they're `constexpr` (or `const` under certain circumstances). If you're using an `int`, the compiler has to assume that you're using negative values.

              > holding both positive and negative number(in signed type) requires more resource than unsigned, is it true?
              An `int` has the same memory footprint as an `unsigned int`. There's no difference.

              > what data type is studentList?
              `std::array<const char*, 5>`

              > Why it's only working with std::size_t/unsigned int?
              `std::array` uses `std::size_t` for indexes, see
              You can't implicitly convert/compare signed and unsigned integers.

              > using vector type instead of array in studentList throws the same complain
              `std::vector` uses some unsigned integer type for indexes as well (Not necessarily `std::size_t` though). See

              • Forhad Rahman

                Sooo... what I understood from your replay is -
                Since studentList is an array(std::array), and std::array uses std::size_t, and std::size_t only supports positive values, and also my compiler will assume I may use negative values using 'int' - that's why the arraySize & index have to be positive. So I have to use unsigned int/std::size_t, am I right?

                > what data type is studentList?
                `std::array<const char*, 5>`
                - Well, till now I know 3 datatype - fundamental, compound, aggregate. No idea in which category does studentList fall into, but I heard there are lot more type than these 3.. bit confused as a newbit :)

    • Hi

      As Alex said, the return of typeid is compiler-specific.  This is just the way your compiler tells you the type.

      A8_i means an "A"rray of size "8" with values of type "i"nt, so putting them together, you get A8_i.  It's a bit cryptic, huh?

      • Forhad Rahman

        Cryptic indeed. This code is showing only the letter 'y'. What am I supposed to understand from here?? -__-

        A bit frustrating for me :/

        • Alex

          Your program reduces down to the following:

          When I ran this, Visual Studio 2019 printed "unsigned int". Your compiler may have std::size_t defined differently. I think 'y' is what g++ prints for unsigned long long.

          If this topic is confusing to you, you can totally skip it. We don't build on it anywhere.

  • Szymon :)

    Why is can static_cast be used without the std:: prefix ?

  • Forhad Rahman

    learncpp -
    Shows how to use C-style cast.

    Also learncpp -
    Avoid using C-style cast.


    Ok, I know it's good to know. But sometimes it bothers xD

  • yeokaiwei

    Are static variables and static casts the same thing?

  • Spero

    Hello, thank you for the tutorial. I'd like to point out a small grammar error near the beginning of the lesson.

    "In the case where you are using literal values (such as 10, or 4), replacing one or both of the integer literal value"
    "value" should be plural
    "In the case where you are using literal values (such as 10, or 4), replacing one or both of the integer literal values"

  • briggets

    You know how in C you could cast structs as function parameters without an identifier like so:

    What's the "C++ way" of doing this using static_cast?

    This doesn't work.

    • nascardriver

      I don't know C, but if `print_coords` has a `Vector2` parameter you can simply construct the `Vector2` in the call

  • SyntaxEra

    // Hello guys, this is simple code
    //  i want to used type conversion (casting) to change  type
    //from integer to double, but I failed. I dont know what is the problem
    // can you help me, please..

    #include <iostream>
    int divi(int,int);  // function prototype
    using namespace std;

    int main() {  
        int x=10; int y =3;
        cout<<x<<" / "<<y<<" is "<< static_cast<double>(divi(x,y));
        return 0;

    int divi(int a, int b){
        return a/b;

    • nascardriver

      The integer division happens in `divi` already, the caller can't do anything about it. You need to cast one of the operands to a `double` and change the return type.

  • Galih

    So i have an array

    Using function find that search a number within myarray, the function will return std::end(myarray) if the number is not found, otherwise find will return pointer to other place.

    If the number is found, the program will print the index within myarray

    Now this got me thinking "what if i want to find out the number of bytes between std::begin(myarray) and found?". After trial and error, i can do it with this

    But this is too tedious, so after looking around, it seems that i can do this instead

    But after looking at this page, it says that reinterpret_cast can be harmful, or in this case it is alright to do this?

    • nascardriver

      `reinterpret_cast` to `char` is allowed to observe bytes. Your specific use of `reinterpret_cast` is allowed, but still discouraged. You don't need any pointer casts at all, because you know the number of elements and the size of each element

      • Galih

        What is decltype? I omitted it and there is no difference in result.

        • nascardriver

          `decltype` "returns" the type of its argument, for example

          `sizeof` also works with variables, so `decltype` can be omitted.

  • sami

    1) I think in the following snippet, you should replace regular initialization to list initialization as that example will compile and doesn't show any compile error with the regular initialization(=).

    2) I found that, when we use list {} with assignment operator, the compiler will produce an error regarding narrowing conversion; otherwise it wouldn't with regular assignment. I didn't know we could use {} with assignment as well as initialization!

  • sami

    When I ran the following, I got error on narrowing conversion from int to float. But you said you got 2. is it because of the compiler?

  • sami

    In the following snippet, do STILL both literal floating point values convert to 'double' as the highest priority?

    • nascardriver

      No, the division is performed using the types of the most precise operand. In your example, the most precise operand is a `float`, so the division is performed with `float`s.

  • P

    Hi, wonderful people!

    Just noticed a spelling error (paragraph before Type Casting):

    "A cast represents an request by the programmer to do an explicit type conversion."

    'an' should be 'a'.

    Thanks for all the hard work, guys!

  • Gabe

    How would a typecast like this work:

    I have seen this done many times but it still evades me as to how you can cast a non-pointer to a pointer. How would this work.

    • nascardriver

      A pointer is just an address. You can cast them to integers and back. If the address you're casting doesn't point to an object of the pointer type, you're causing undefined behavior.

      C-style casts are unsafe, they allow conversions that cause UB. You can do the same with a `reinterpret_cast`, but it's more obvious that this isn't a safe cast.

      • Gabe

        uintptr_t is not a pointer in and of itself, but capable of storing a pointer. I think it was misleading what I wrote.

        so uintptr_t is a regular data type, unsigned long i believe.

        But this doesn't make sense to me, because it is never taught how a non-pointer to a pointer cast works.

        • nascardriver

          It's not taught, because it's unsafe and rarely useful. Unless you're doing low-level memory operation (Potentially intentionally invoking UB), there's no need to cast pointers to integers and back.

          • Gabe

            Vice-versa, i mean. Integers to pointers. This is what I need to know. I understand now cstyle casts should generally be avoided.. But I need to know how this particular operation works to see if there is a better cast for it.

            And yes this is dealing with low-level memory operations.

            • nascardriver

              Enter undefined behavior land. Virtually every compiler does what you want, but it doesn't have to.
              A pointer is nothing but a number (The memory address). When you use a pointer, the memory at that address is read from, or written to.

              Unlike a `static_cast`, a `reinterpret_cast` changes only the type, not the data.

  • kitabski

    First of all, Thanks for awesome tutorial!!!
    Can anyone help me?
    So the result of the follwing is 2.5

    But if i change it a bit and put i1 and i2 into brackets (i1/i2), the result is 2.

    • nascardriver

      `i1 / i2` is performed first. Since both are `int`, the result is an `int` (2). You're then casting the 2 to `float`, but the precision has already been lost.

      `i1` is cast to `float` first. Then you're dividing `float` by `int`, which produces a `float`.

  • Radioga

    I have a doubt about this sentence: "Because C-style casts are not checked by the compiler at compile time, C-style casts can be inherently misused". In my experience the C-style cast is checked by the compiler; for example this little program cannot compile:

    the output console of Visual Studio 2017 says me:

    error C2440: 'type cast': cannot convert from 'float' to 'char **'

    • Alex

      I've updated the article a bit with better reasons not to use C-style casts, and added a link with more detail on how C-style casts work for the curious. Thanks!

  • daniel jo

    "Static_cast takes as input a values" this bit confuses me.. can u explain what u mean

  • Q

    Can you give more examples of why c++ style cast should be preferred? C style casts have always worked fine for c and java for that matter. I don't understand why they took something simple from C and replaced it with this over complicated ugly, and cumbersome mess. What ever happened to if it ain't broke don't fix it?

    • Alex

      C++ style casts should be preferred because:
      1) They allow you to better express your intent.
      2) C-style casts might do any number of things (and sometimes different things depending on context), and it's not always clear which one is being invoked from reading the code.
      3) They're easier to find in your code precisely because they're "ugly" and differentiated.
      4) At least in the case of dynamic_cast<>, they can do things that C-style casts can't.

      There's nothing that says you have to give up C-style casts if you want to, but C++ styles casts are safer. has a little bit of additional information as well as an example of where C-style casts can go wrong.

  • James

    In order to announce to the compiler that you are explicitly doing something you recognize is potentially unsafe (but want to do anyway), you can use a cast
    I believe that's not actually what happened there. "static_cast" is an unary operator with high precedence level(2) which takes in one expression of a type and return that expression with the type programmer desired. So, compiler giving a warning for doing unsafe conversion on type-converting operator which purpose is to convert type makes no sense, so it won't. And when we do "i = static_cast<int>(i / 2.5);", "static_cast<int>(i/2.5);" will be evaluated first since "static_cast" operator has higher precedence lever than "operator=". When compiler evaluate "operator=", it see an int being assigned to an int so no warning.
    I've confirmed it by using -Wconversion I found in a comment by @nascardriver. Try something like "float x= 3; int y = static_cast<double>(x);" and see your compiler still give warning even when you're using "static_cast".

    • Alex

      I take your point -- the original wording left something to be desired. I've updated the lesson text to be more explanatory around what's happening without losing the "programmer is taking responsibility" angle.

  • Anonymous

    Why should casting be avoided? Wouldn't it be better to use (static) casting always instead of letting it happen implicitly?

  • jih332

    Hi there,  
    You said that "In the following program, the compiler will typically complain that converting a double to an int may result in loss of data:"

    however I didn't find any issue by doing this on my side, I'm using

    to compile my code. what could be the reason for this? Thanks in advance.


    what is type cast operator?

    #include <iostream>
    using namespace std;

    class A {};

    class B {
      // conversion from A (constructor):
      B (const A& x) {}
      // conversion from A (assignment):
      B& operator= (const A& x) {return *this;}
      // conversion to A (type-cast operator)
      operator A() {return A();}

    int main ()
      A foo;
      B bar = foo;    // calls constructor
      bar = foo;      // calls assignment
      foo = bar;      // calls type-cast operator
      return 0;

  • Benur21

    Can we use

    in C++?

    Also, what do you mean by getting rid of a const?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]