I have often wondered what exactly does casting do at compiler or machine level. What does it do with the 0 and 1s in memory?
Can anyone point me at some good literature.
I have often wondered what exactly does casting do at compiler or machine level. What does it do with the 0 and 1s in memory?
Can anyone point me at some good literature.
Assuming this is just a reference type cast rather than a conversion (e.g. int to byte), I believe it does the following:
1) Check if the reference is null - if so, quit.
2) Follow the reference to find the object in memory. In the object header, there's information saying what the type is.
3) From the type information, check whether the target type is in the hierarchy. If it's not, throw a ClassCastException
with appropriate information.
The "bits" of the result are always the same as the "bits" of the input (assuming there is an output rather than an exception), but then the JVM knows the type of the reference so other operations are guaranteed to succeed.
Casting doesn't modify the individual bits when casting between reference types, it just instructs the compiler/runtime to interpret the bits in a specific way if possible.
If the cast is not possible at compile time due to incompatible types an error is issued. If the cast is not possible at runtime an exception is thrown.
The wiki page on type conversion has additional information.
It depends on what you cast. For numeric casts, (float to int and back), the CPU will try to find the closest number which fits into the destination.
For type cases, it doesn't do anything to memory. It's just a way for the software developer to tell the stupid compiler that some variable for once should be treated as if it was of a different type.
I tried to google some informations about rules for numeric casting but there isn't much around. You can try the C99 standard but I'm not sure whether it will overwhelm you. IIRC, the rules are:
Casting down (big type -> smaller type like double -> float -> int -> byte) will cut off information which can't be represented (so double->float will lose precision, -> int will lose all decimal places + no rounding).
Casting up (smaller type -> bigger type) means to fill the additional bits with '0'.
Of course, there are numbers which you can't really represent (like 0.1). Any operation on these even without casting will lose information (which is why 0.1*10 can be != 1.0).
In C for non numeric types, casting does nothing on 0 and 1s in memory.
For numeric types, the C compiler makes conversion so that numeric value remains the same, as much as possible.
If you do want to cast numeric types without changing bit values, you have to use a union or cast pointers (following code illustrates the latter):
float a;
int b = 3;
a = *((float*)&b);
Regarding Casting, a useful literature would be the JavaTM Virtual Machine Specification.
At the section Conversions and Promotions, you would see there is six broad kinds of conversions:
There are five conversion contexts in which conversion expressions can occur, including the Casting Conversion:
Casting contexts allow the use of:
- an identity conversion,
- a widening primitive conversion,
- a narrowing primitive conversion,
- a widening reference conversion, or
- a narrowing reference conversion.
Thus, casting conversions are more inclusive than assignment or method invocation conversions: a cast can do any permitted conversion other than a string conversion.
Casting can convert a value of any numeric type to any other numeric type. A value of type boolean cannot be cast to another type. A value of reference type cannot be cast to a value of primitive type.
Some casts can be proven incorrect at compile time and result in a compile-time error. Otherwise, either the cast can be proven correct at compile time, or a runtime validity check is required. (See The JavaTM Language Specification for details.)
If the value at run time is a null reference, then the cast is allowed. If the check at run time fails, a ClassCastException is thrown.
See this current question:
http://stackoverflow.com/questions/674982/performance-hit-from-c-style-casts
One needs to also understand how references work at both compile and runtime time.
Each and every type holds a lookup table for each and every method which resolves each method to the most resolved method for that type.
So if your reference is a Object calling toString() does the right thing and finds the most derived toString() method. Casting is necessary to allow the runtime to guarantee that any given reference really has target methods for each method exposed on the reference. After passing the cast from X to Y any reference of type Y can be assured that all its methods are available on the casted(sp) reference.
Others have covered the basics, but I'd like to say a few words about how a compiler is implemented that may be enlightening in his case.
The compiler maintains a list (called the symbol table) of variable names in use at any particular point in the program and some information about the variables. The list of information includes:
SubWhatsitObj
) including any restriction (like for instance constantness)The compiler uses this information to decide how to treat expressions involving the variables. The kind of meta-information that is stored in the symbol table can also be derived for any expression from it's components.
Except in the special case of numeric type conversion, a cast just tells the compiler to use different meta-information for a variable or expression than would usually be the case. No bits in memory are affected at all, but the outcome of a calculation may be.