Navigation



4.4 — Type conversion and casting

Previously, you learned that the value of a variable is stored as a sequence of bits, and the data type of the variable tells the compiler how to translate those bits into meaningful values. Often it is the case that data needs to be converted from one type to another type. This is called type conversion.

Implicit type conversion is done automatically by the compiler whenever data from different types is intermixed. When a value from one type is assigned to another type, the compiler implicitly converts the value into a value of the new type. For example:

double dValue = 3; // implicit conversion to double value 3.0
int nValue = 3.14156; // implicit conversion to integer value 3

In the top example, the value 3 is promoted to a double value and then assigned to dValue. The compiler will not complain about doing this. However, some type conversions are inherently unsafe, and if the compiler can detect that an unsafe conversion is being implicitly requested, it will issue a warning. In the second example, the fractional part of the double value is dropped because integers can not support fractional values. Because converting a double to an int usually causes data loss (making it unsafe), compilers such as Visual Studio Express 2005 will typically issue a warning. Other unsafe conversions involve assigning unsigned variables to signed variables (and vice-versa), and assigning large integers (eg. a 4-byte long) to integer variables of a smaller size (eg. a 2-byte short).

Warning: Microsoft’s Visual C++ 2005 does not seem to issue warnings for unsafe signed/unsigned conversions.

When evaluating expressions, the compiler breaks each expression down into individual subexpressions. Typically, these subexpressions involve a unary or binary operator and some operands. Most binary operators require their operands to be of the same type. If operands of mixed types are used, the compiler will convert one operand to agree with the other. To do this, it uses a heirarchy of data types:

Long double (highest)
Double
Float
Unsigned long int
Long int
Unsigned int
Int (lowest)

For example, in the expression 2 + 3.14159, the + operator requires both operands to be the same type. In this case, the left operand is an int, and the right operand is a double. Because double is higher in the heirarchy, the int gets converted to a double. Consequently, this expression is evaluated as 2.0 + 3.14159, which evaluates to 5.14159.

A good question is, “why is integer at the bottom of the tree? What about char and short?”. Char and short are always implicitly promoted to integers (or unsigned integers) before evaluation. This is called widening.

This heirarchy can cause some interesting issues. For example, you might expect the expression 5u - 10 to evalute to -5 (5u means 5 as an unsigned integer). But in this case, the signed integer (10) is promoted to an unsigned integer, and the result of this expression is the unsigned integer 4294967291!

Many mixed conversion work as expected. For example, int nValue = 10 * 2.7 yields the result 27. 10 is promoted to a float, 10.0 * 2.7 evaluates to 27.0, and 27.0 is truncated into an integer (which the compiler will complain about).

Many new programmers try something like this: float fValue = 10 / 4;. However, because 10 and 4 are both integers, no promotion takes place. Integer division is performed on 10 / 4, resulting in the value of 2, which is then implicitly converted to 2.0 and assigned to fValue!

In the case where you are using literal values (such as 10, or 4), replacing one or both of the integer literal value with a floating point literal value (10.0 or 4.0) will cause both operands to be converted to floating point values, and the division will be done using floating point math.

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

int nValue1 = 10;
int nValue2 = 4;
float fValue = nValue1 / nValue2;

fValue will end up with the value of 2. How do we tell the compiler that we want to use floating point division instead of integer division? The answer is by using a cast.

Casting

Casting represents a request by the programmer to do an explicit type conversion. In standard C programming, casts are done via the () operator, with the name of the type to cast to inside. For example:

int nValue1 = 10;
int nValue2 = 4;
float fValue = (float)nValue1 / nValue2;

In the above program, we use a float cast to tell the compiler to promote nValue1 to a floating point value. Because nValue1 is a floating point value, nValue2 will then be promoted 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:

int nValue1 = 10;
int nValue2 = 4;
float fValue = float(nValue1) / nValue2;

The C style cast can be inherently misused, because it will let you do things that may not make sense, such as getting rid of a const or changing a data type without changing the underlying representation. C++ introduces a new casting operator called static_cast. A static cast works similarly to the C style cast, except it will only do standard type conversions, which reduces the potential for inadvertant misuse:

int nValue1 = 10;
int nValue2 = 4;
float fValue = static_cast<float>(nValue1) / nValue2;

As mentioned above, compilers will often complain when an unsafe implicit cast is performed. For example, consider the following program:

int nValue = 48;
char ch = nValue; // implicit cast

Casting an int (4 bytes) to a char (1 byte) is potentially unsafe, and the compiler will typically complain. In order to announce to the compiler that you are explicitly doing something you recognize is potentially unsafe (but want to do anyway), you should use a static_cast:

int nValue = 48;
char ch = static_cast<char>(nValue);

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

int nValue = 100;
nValue = nValue / 2.5;

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

int nValue = 100;
nValue = static_cast<int>(nValue / 2.5);

Casting should be avoided if at all possible, because any time a cast is used, there is potential for trouble. But there are many times when it can not be avoided. In these cases, the C++ static_cast should be used instead of the C-style cast.

4.5 — Enumerated types
Index
4.3 — File scope and the static keyword

61 comments to 4.4 — Type conversion and casting

  • [...] If no exact match is found, C++ tries to find a match through promotion. In the lesson on type conversion and casting, we covered how certain types can be automatically promoted via internal type conversion to other [...]

  • [...] — Overloading typecasts By Alex In the lesson on type conversion and casting, you learned that C++ allows you to convert one data type to another. The following example shows [...]

  • Cody

    Don’t you mean putting a signed variable into an unsigned variable is dangerous?

    [ It's dangerous either way. I updated the text to reflect this. -Alex ]

    • Chip Blach

      Casting is at the discression of the programmer. I have had cases where I have had to cast an integer
      as a array of 4 unsigned chars.
      If the program needs it, cast it, if it does not, dont do it.

      In c++ it is always better not to cast, but to stick with strict assignments which are provided.

      Chip

  • Abhishek

    This paragraph(and anything after it)went over my head::

    “The C style cast can be inherently misused, because it will let you do things that may not make sense, such as getting rid of a const or changing a data type without changing the underlying representation. C introduces a new casting operator called static_cast. A static cast works similarly to the C style cast, except it will only do standard type conversions, which reduces the potential for inadvertant misuse”
    ================================================
    I didn’t get the difference b/w Cpp style cast,C style cast and static_cast…………I think all of them do the same thing…only the syntax is different.????
    ================================================

    • The purpose of static_cast is to do normal conversion between types without runtime checks. C++ provides several other types of casts, including dynamic_cast, reinterpret_cast, and const_cast, all of which have different behavior.

      The problem with C-style casting is that it may use a static_cast, reinterpret_cast, or const_cast (or a combination thereof) depending on the situation, and we’re not always sure which one(s) it’s going to pick. That’s why using static_cast is safer — we’re always sure what it’s going to do, and if we try to do something it wasn’t meant for, it will give us a warning.

      Here’s an example of a C-style cast:

      const char *strMsg="Can't touch this!";
      unsigned char *ptr=(unsigned char*)strMsg;
      

      Not only is this casting a char to an unsigned char, it’s also tossing away the const. I think it’s doing a reinterpret_cast and a const_cast combination. In any case, you can see that this is dangerous. Let’s try using a C++ style static_cast instead:

      const char *strMsg="Can't touch this!";
      unsigned char *ptr=static_cast(strMsg);
      

      When we try to compile this, the compiler will complain:

      C:\Test.cpp(46) : error C2440: 'static_cast' : cannot convert from 'const char *' to 'unsigned char *'
              Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
      

      In other words, the C++ style casts give you more control over what type of casting you want to perform, and will warn you if you do something that violates the constraints on the cast. On the other hand, C-style casts will try to convert whatever you throw at it, regardless of whether it really makes sense to be doing so. This is dangerous and can lead to unexpected behavior.

  • Allen01

    When I build and compile the code below, the output is -5. You mention that:

    “This hierarchy can cause some interesting issues. For example, you might expect the expression 5u – 10 to evalute to -5 (5u means 5 as an unsigned integer). But in this case, the signed integer (10) is promoted to an unsigned integer, and the result of this expression is the unsigned integer 4294967291!”

    Is the hierarchy issue compiler specific? I am using VC 2005 Express.

    #include “stdafx.h”
    #include 
    
    int main()
    {
    using namespace std;
    int x;
    x = 5u – 10;
    cout < < x;
    return 0;
    }
    
    • The issue is in how you’ve written your program. This is a tricky one.

      For example, if you do this:

      cout < < 5 - 10u;
      

      You get 4294967291.

      If you do this:

      int x= 5u - 10;
      cout < < x;
      

      You get -5.

      So what's the difference? The answer has to do with the way types are promoted. When the compiler encounters 5 - 10u, it promotes 5 to an unsigned value, and 5u - 10u produces the result 4294967291 (unsigned). However, it's worth noting that 4294967291u and -5 have the exact same bit pattern -- the interpretation depends entirely on whether the value is treated as signed or unsigned.

      Because 5 - 10u produces an unsigned value, cout treats it as an unsigned value, and prints 4294967291 as the result.

      However, in your case, you've assigned this unsigned value back to a signed integer. Because x is signed, when you print x in the next statement, cout prints the value as if it were signed, which is why it prints -5.

      So the ultimate answer is that the statement as written is true. You've simply cast 4294967291 unsigned back to a signed integer and printed that value, which is the value you were intuitively expecting anyway. :)

  • i have a problem i want to do get input from user then i want to do the multiplication,division,subtraction,addititon,and modulus by using type double.How i will do modulus with double variable any one can provide me the code

  • [...] 2007 Prev/Next Posts « 4.2 — Global variables | Home | 4.4 — Type conversion and casting » Tuesday, June 19th, 2007 at 5:46 [...]

  • Shankar

    I find that if nValue1 and nValue2 are char and they are set to the max value (127), then assigning nValue1 + nValue2 to fValue results in the correct value (254) instead of -2. Similarly also for short int, but not for int. With int, unless at least one is type cast to float, the answer is -2. This behavior I find with Visual Studio 2005.

  • Alok

    Even after using static_cast, i am getting compiler warning “warning (etoa:1643): narrowing or signed-to-unsigned type conversion found: unsigned long to unsigned short”.

    I am trying to assigned int variable to short int variable.

  • spacedmonkey

    Hi,

    I just have a query about casting. When you cast a variable from one type to another in order to carry out some statement or other, is the variable permanently changed to this type or is it just temporarily changed at the point where the cast command is used?

    For instance:

    int nValue1 = 10;
    int nValue2 = 4;
    float fValue = static_cast<float>(nValue1) / nValue2;

    nValue1 is cast as a float in line 3 (and nValue2 is changed to a float as well I assume). Is nValue1 (and nValue2) a float from this point on in the program or does it retain its original type of int?

    • Anu

      Hi spacedmonkey,

      I tried to answer your question…by running the following code:

      int nValue1 = 10;
      int nValue2 = 4;
      float fValue = static_cast<float>(nValue1) / nValue2;
      
      cout << "fValue is " << fValue << endl;
      cout << "nValue1 is " << nValue1<< endl;
      cout << "nValue2 is " << nValue2<< endl;
      

      The output is 2.5, 10 and 4
      So, this means that the values of nValue1 and nValue2 are temporarily casted as floats, just for evaluating that expression.

    • They are temporarily cast. If you don’t assign those temporary values to anything, they are lost. The original variable is not changed.

  • value of a variable or
    value of the variables, not
    value of a variables

    [ Fixed. Thanks! -Alex ]

  • csvan

    I am not entirely clear on the second-last example of this page: About half-way through the tutorial, it is explained that since double has higher precedence then int, an arithmetic operation on an int and a double will cause the int to be turned into a double. Yet, here (the second last example), it is stated that the compiler will complain about a double being converted to an int!

    Is there thus a difference between first EXPLICITLY declaring a variable of a certain type and then using that variable in an arithmetic operation with an implicitly defined variable (such as 2.5), as opposed to have two implicitly declared and defined variables in an arithmetic operation (such as 2 / 2.5)?

    • jdurham

      when promoting an int to a double there is no warning because the int is increasing in precedence (changing a 2 to a 2.0 does not cause any unwanted behavior).

      The compiler will warn you about lowering the precedence of a value, which happens when you convert a double to an int. (Chaning 2.5 into an int results in 2, so the .5 gets lost)

  • Aaron

    hi for the second example, im trying to use casting to convert the equation dividing 2 integers into a float using static_cast but it keeps returning an int. any pointers? the line of code i am using is :

    cout << “Your fractions multiplied together = ”
    << static_cast(sFraction1.nNumerator*sFraction2.nNumerator)/(nFraction1.nDenominator*sFraction2.nDenominator);

  • Zak

    After doing:

    	int nValue7 = 48;
    	char chUnsafe = static_cast(nValue7);
    	cout << "chUnsafe = " << chUnsafe << endl;
    	cout << endl;  //Prints 2
    
    

    It printed out 0.

    After doing:

    	int nValue7 = 48;
    	char chUnsafe = static_cast(nValue7);
    	cout << "chUnsafe = " << (int)chUnsafe << endl;
    	cout << endl;  //Prints 48
    

    It printed out 48.

    So what does the number 48 convert to as a character? Why did it come out as 0? Is that the character it was assigned?

    • TBM

      Simply put yes a decimal of 48 converts to a binary of 0011 0000 which is = to a hex value of 30 which evaluates to 0 as a char. Incrementing nValue7 to 49 would return 1 and 50 would return 2 and so on. Remember that an int number and a char number are not necessarily the same binary value.

  • Kjell

    Is it possible to convert a char or a string to int or double with the same human reading? Like you have a char[] 2.2 and want to convert it to a double with 2.2 as value.

  • Dan

    A good programmer would know what he is doing and not need coddling with extra, complicated syntax to explicitly tell it what to cast it as.

    (char)
    is so much easier to type than:
    static_cast…

  • x = static_cast(stuff);

    the type inside is what you want it to be converted TO?

  • Mkc

    Thank you! I read about this in a book a while back and just didn’t get the point. Now I do!

    Your real world examples and “new programmers tend to do this” advice make this a fantastic tutorial.

  • [...] For more inform­a­tion in C/C++ type cast­ing issues, have a look at the fol­low­ing web page: http://www.learncpp.com/cpp-tutorial/44-type-conversion-and-casting/ [...]

  • [...] 4.4 Type conversion and casting [...]

  • Skaptor

    Hello, I have a problem, CodeWarrior shows up an error when trying to compile a project i doing,
    the compiler says “Missing ´}´ on line 499, what Im I doing wrong hope you can help me

    void main(void)
    {
    Sys_Peripheral_Init();
    int nValue; //this is line 499
    ClearDisplay();
    string = ” JUANCAR SAYS “;
    ScrollString(string);

    for (j=0 ; j<3 ; j++)
    {
    for (i=1 ; i<10000 ; i++);
    }

    _PTCD.Byte = 0;
    _PTBD.Byte = 0;

    //A sequence for some LEDs goes here

    int nValue = 1;
    char count = nValue; // implicit cast im trying to do

  • surya

    hi…
    i am unable to understand what happens when a static cast is applied to pointers to objects of different types.

    if we do like

    int i;
    float f =24.56;
    i=static_cast(f);

    here there is loss of data.

    In the same way, can i use static cast like this

    class ex1
    {
    int a;
    float b;
    public:
    ex1()
    {
    a=10;
    b=2.3;
    }
    };

    class ex2
    {
    double d;
    public:
    ex2()
    {
    d=23.44;
    }
    };
    int main()
    {
    ex1 *p1= new ex1();
    ex2 *p2;

    p2=static_cast(p1); //is this correct??

    if it is correct …what does p2 contain now??

    what does the compiler do here??

  • surya

    sry

    p2=static_cast(p1);

  • surya

    p2=static_cast<>(p1);

  • surya

    ohhh…sry ZINGMARS…….i didnt notice it…now i have uploaded my code at http://pastebin.mozilla.org/1253503…….please clarify my doubt as early as possible………

    Thanks,
    Surya

    • This is what compiler does too – it does whatever you ask from it, and assigns the results to a memory location, and then you store it in p1.
      And no – the line does not work. Firstly because apparently you can’t do static cast on pointers (they’re memory locations, not values or types or anything).
      Also – one does not simply convert one class to another. It doesn’t work that way.
      Just my 2 cents.
      So I guess the answer to the ‘what does it hold’ is – nothing. It holds nothing because you can’t do things this way.

  • surya

    thank you zingmars

  • Konda

    Hello, I have a question: Is it safe to use static_cast([float value here]) to truncate a float value? And no, I’m not talking about rounding.

  • [...] If no exact match is found, C++ tries to find a match through promotion. In the lesson on type conversion and casting, we covered how certain types can be automatically promoted via internal type conversion to other [...]

  • SamHocevar

    I would like to point out that “int nValue = 10 * 2.7″ does not really work “as expected”. It is not possible to store the value 2.7 in a double. Instead, the value stored in the machine register is something like 2.7000000000000001776… (continuing to 51 digits). You are lucky that the IEEE rounding rules allow the computation to give 27 at the end, but in general you should never expect a floating-point computation on inexact values to give an exact result.

    The value 2.5 can be represented exactly as a double, however. So you are guaranteed that 10 * 2.5 will be 25.

  • vinu

    The following snippet of code explained in this chapter isn’t working as described.

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

    int nValue = 100;
    nValue = nValue / 2.5;

    my code:
    {
    int ivalue = 100;
    cout << "output" << ivalue/2.5 <<endl;
    ivalue = ivalue / 2.5;
    cout << "ivalue" <<ivalue << endl;
    return 0;
    }

    Both the cout returns 40, no compiler warning or error. I am using codeblocks.

    secondly, if the hierarchical nature of type conversion is true then why doesn't the following implicit cast of ivalue produce compiler error ?
    int main()
    {
    int ivalue = 0;
    double dvalue1 = 3.54567;
    double dvalue2 = 2.34345;
    ivalue = dvalue1 / dvalue2;
    cout << "ivalue" <<ivalue << endl;
    return 0;
    }

  • [...] If no exact match is found, C++ tries to find a match through promotion. In the lesson on type conversion and casting, we covered how certain types can be automatically promoted via internal type conversion to other [...]

  • [...] If no exact match is found, C++ tries to find a match through promotion. In the lesson on type conversion and casting, we covered how certain types can be automatically promoted via internal type conversion to other [...]

  • [...] the lesson on type conversion and casting, you learned that C++ allows you to convert one data type to another. The following example shows [...]

  • This heirarchy can cause some interesting issues. For example, you might expect the expression 5u – 10 to evalute to -5 (5u means 5 as an unsigned integer). But in this case, the signed integer (10) is promoted to an unsigned integer, and the result of this expression is the unsigned integer 4294967291!

    “Interesting” is one way to describe it….

  • Thanks for all these great examples and the helpful summary. Next time someone asks me why type safety matters I’m going to send them here.

  • joel.giedt

    One common type casting that comes up all the time in codes I work with is switching between different types of pointers. The most unavoidable example is something like

    Float *ptr = (Float *)smalloc(num_bytes);

    Because smalloc() is like malloc in that it returns a void type. You might wonder why not use the new operator for dynamic allocation? The reason is that on the architecture we are using (e.g., BlueGene L/P/Q) we want to align the memory usage properly in order to avoid cache misses. So we write a function smalloc() that takes care of all that for us, which new would not do if we are using the GNU compiler (maybe IBM’s compiler will do it automatically, I don’t know). We can also write into it code to verify the allocation was successful and if not, report the class and function where the error occured,

    Float *ptr=(Float *)smalloc(num_bytes,cname,fname);

    Also Float is some typedef, probably float or double, depending on the precision we’ve decided to use.

    Another use, which looks dangerous, but we do it anyways because we care more about performance than C++ doctrine, is something like:

    int num_bytes = N*2*sizeof(Float);
    Complex *c=(Complex *c)smalloc(num_bytes);
    // next, code that fills in the array of complex numbers …
    Float *temp=(Float *)c;
    // Now we want the norm of the complex vector, and we use an optimized function that say uses standard reduction algorithm to take advantage of multithreading on our 64-way processor, or maybe on a GPU accelerator:
    Float my_norm=norm(temp,N*2);

    By converting to Float array, the complex array looks just like an array of floats 2*N long and norm knows what to do with such an array. If norm is a library function that we a calling from some external package, it probably has no idea what to do with our abstract Complex type. So we trick it. Is it “dangerous”? Maybe, but so is driving a car.

    Another trick may be if we have to call MPI_Send() and MPI_Recv() to send the array of Complex numbers between compute nodes. Then Float* typically means something to these functions, but Complex* does not. It would be ridiculous to copy the array elements into a float array just to communicate them when a simple type casting does the job (provided we do not use the C++ standard complex class, but rather our own class with just two data elements — note that they also cannot be private, again for performance reasons — we’d be friending practically every function in our code, which is plain silly).

You must be logged in to post a comment.