Previously, you learned that the value of a variables 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 ]
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.