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
|
4.5 — Enumerated types
Index
4.3 — File scope and the static keyword
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 ]
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
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:
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:
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 castIn 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.
Thanks…
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.
The issue is in how you’ve written your program. This is a tricky one.
For example, if you do this:
You get 4294967291.
If you do this:
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. :)
so in his case, two wrongs made a right?
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
Modulus is an integer operation and can not be used with doubles.
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.
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.
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:
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?
Hi spacedmonkey,
I tried to answer your question…by running the following code:
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 ]
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)?
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)
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);
After doing:
It printed out 0.
After doing:
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?
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.
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.
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?
the type inside is what you want it to be converted TO?
(sry for reposting but the brackets didnt show)
Yes. The type can be int, float, char, double..etc
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.