A type conversion ( English type conversion , typecasting , coercion ) in computer science converts a value of one type into a value of another type.
Content
Description
There are cast types:
- explicit ( eng. explicit );
- implicit ( English implicit ).
The explicit cast is set by the programmer in the program text using:
- language constructs;
- a function that takes a value of one type and returns a value of another type.
Implicit casting is performed by a translator ( compiler or interpreter ) according to the rules described in the language standard. Standards in most languages prohibit implicit conversions.
In weakly typed object-oriented languages, such as C ++ , the inheritance mechanism is implemented by casting the type of pointer to the current object to the base class (in type-safe ones , such as OCaml , the concept of type casting is absent, and the validity of accessing the subtype component is controlled by the matching mechanism types at the compilation stage, and in the machine code there remains a direct appeal).
Implicit type casting
Implicit type conversion in C / C ++ languages
Implicit type conversion occurs in the following cases [1] :
- after computing the operands of binary arithmetic, logical, bit operations, comparison operations, as well as the 2nd or 3rd operand of the “?:” operation; operand values are of the same type;
- before performing the assignment;
- before passing the function argument;
- before return function return value;
- after evaluating the expression of the
switch
construction, the value is converted to an integer type; - after evaluating the expressions for
if
,for
,while
,do
-while
constructions, the value is converted to thebool
type
For example, when performing a binary arithmetic operation, the values of the operands are reduced to the same type. When inheriting, the derived class pointers are cast to the base class pointers.
Consider an example in C.
double d ; // real type
long l ; // whole type
int i ; // whole type
if ( d > i ) d = i ;
if ( i > l ) l = i ;
if ( d == l ) d * = 2 ;
When performing comparison operations and when assigning, variables of different types are implicitly reduced to the same type.
With implicit conversions, side effects are possible. For example, when converting a number of a real type to an integer type, the fractional part is cut off (no rounding is performed). In the case of the inverse transformation, a decrease in accuracy is possible due to differences in the representation of real and integer numbers. For example, in a variable of type float
( a single-precision floating-point number according to IEEE 754 ), you cannot save the number 16,777,217 without loss of accuracy, but in a 32-bit integer variable of type int
, you can. Due to the loss of accuracy, the comparison operation of the same number represented by integer and real types (for example, int
and float
) may give false results (the numbers may not be equal).
#include <stdio.h>
int main ( void )
{
int i_value = 16777217 ;
float f_value = 16777216.0 ;
printf ( "The integer is:% d \ n " , i_value );
printf ( "The float is:% f \ n " , f_value );
printf ( "Their equality:% d \ n " , i_value == f_value );
}
The above code will output the following if the int
size is 32 bits and the compiler supports the IEEE 754 standard:
The integer is: 16777217 The float is: 16777216.000000 Their equality: 1
Type explicit cast
Type C casting
For an explicit type conversion, the type name is indicated in parentheses in front of the variable or expression. Consider an example.
int X ;
int Y = 200 ;
char C = 30 ;
X = ( int ) C * 10 + Y ; // variable C is cast to type int
To calculate the last expression, the compiler performs the following actions:
- First, the variable
C
character typechar
explicitly reduced to the integer typeint
by expanding the bit depth ; - Operands are calculated for the multiplication operation. The left operand is of type
int
. The right-hand operand is a constant10
, and such constants areint
by default. Since both operands of the “ * ” operator are of typeint
, implicit type conversion is not performed. The result of multiplication is also of typeint
; - The operands of the addition operation are calculated. The left operand - the result of multiplication is of type
int
. The right-hand operand variableY
is of typeint
. Since both operands of the “ + ” operator are of typeint
, implicit coercion to a common type is not performed. The result of the addition is also of typeint
; - execution assignment. The left operand - the variable
X
is of typeint
. The right-hand operand is the result of evaluating an expression written to the right of the “ = ” sign, also of typeint
. Since both operands of the “ = ” operator have the same type, implicit type casting is not performed.
Even so, mistakes are possible. The char
type can be either signed ( signed char
) or unsigned char
; the result depends on the compiler implementation and this behavior is allowed by the standard. The value of the unsigned char
type when converting to the signed int
type may turn out to be negative due to the implementation of machine instructions on some processors . To avoid ambiguities, it is recommended to explicitly specify char for a type of char
.
C ++ Type Conversions
In C ++, there are five operations for explicit type conversion. The first operation - parentheses ( ( type_to ) expression_from
) is supported to maintain compatibility with C. The remaining four operations are written as
xxx_cast <type_to> (expression_from)
Consider an example.
y = static_cast < signed short > ( 65534 ); // y will be assigned the value -2
Bulky keywords are a reminder to the programmer that casting is fraught with problems.
static_cast
operation
Purpose: valid type conversions.
The static_cast
operation is similar to the “parentheses” operation with one exception: it does not perform pointers to unrelated types (for this, the reinterpret_cast
operation is used).
Application:
- conversion between numeric and enum, including if an implicit conversion is impossible (
int → enum class
) or results in the warning “Possible loss of accuracy” (double → float
); - casting pointers to
void *
type and vice versa; - casting pointers to derived types to pointers to basic types and vice versa;
- selection of one of several overloaded functions ;
bool myLess ( const wchar_t * , const wchar_t * );
bool myLess ( const std :: wstring & , const std :: wstring & );
std :: vector < std :: wstring > list ;
std :: sort ( list . begin (), list . end (), static_cast < bool ( * ) ( const std :: wstring & , const std :: wstring & ) > ( myLess ));
- explicitly call a constructor with a single argument or an overloaded cast operation;
struct Type {
// constructor with one argument to cast the int type to the Type
Type ( int );
// overloaded operation to cast Type to double
operator double () const ;
};
int main () {
Type x , y ;
int i ;
double d ;
// call constructor with one argument
x = y + static_cast < Type > ( i );
// call overloaded type conversion operation
d = static_cast < double > ( x );
return 0 ;
}
- the constructor may have more arguments, but default values must be specified for them;
struct Type {
// constructor with several arguments for casting a Type to an int;
// for the 2nd and subsequent arguments default values are given
Type ( int , int = 10 , float = 0.0 );
};
- type casting in templates (the compiler, when specializing a template, decides which operations to use);
- casting the operands of the ternary conditional operation “
?:
” to the same type (the values of the 2nd and 3rd operands must be of the same type);
Restrictions on expression_from
: no.
Restrictions on type_to
: there must be a way to convert the value of expression_from
to type_to
by using the operator type_to
or constructor.
Does the operation static_cast
code: in general, yes (for example, a call to an overloaded type conversion operation or a constructor).
Sources of logical errors:
- It is possible that after the type conversion, a temporary object will appear, which will be safely destroyed with all the changes. Most compilers issue a warning.
- Overflows are possible when converting numbers.
Examples
// Get the hit percentage.
double hitpercent (
const int aHitCount , // number of hits
const int aShotCount // number of shots
) {
if ( aShotCount == 0 ) return 0.0 ;
// Type casting to double is performed to perform real (not integer) division
return static_cast < double > ( aHitCount * 100 ) / static_cast < double > ( aShotCount );
}
// the following lines are equivalent
// use the static_cast operation
string s = static_cast < string > ( "Hello!" );
// call constructor with one argument
string s = string ( "Hello!" );
// use the operation "parentheses"
string s = ( string ) "Hello!" ;
string s = static_cast < string > ( 5 ); // does not compile, the compiler cannot find a suitable constructor
dynamic_cast
operation
Purpose: coercion down the inheritance hierarchy, with a special behavior if the object does not have the desired type.
The operation retrieves information about the type of the expression_from
object using RTTI . If the type is type_to
or its subtype, the cast is performed. Otherwise:
- for pointers, returns NULL ;
- For links, an exception
std :: bad_cast
.
Restrictions on expression_from
: an expression must be a reference or a pointer to an object that has at least one virtual function .
Restrictions on type_to
: reference or pointer to a child with respect to expression_from
type.
Does the operation dynamic_cast
code: yes.
Logical errors are possible if operations pass an argument that does not have type_to
type and does not check for a pointer to NULL
equality (respectively, do not handle the exception std :: bad_cast
).
Operation const_cast
Purpose: removal / installation of modifier (s) const
, volatile
and / or mutable
. Often this is used to bypass the unsuccessful architecture of a program or library, to dock C with C ++, to transfer information through generalized void*
pointers.
Restrictions on expression_from
: an expression must return a reference or pointer.
Restrictions on type_to
: type_to
type must match the type of expression_from up to modifier (s) const
, volatile
and mutable
.
Does the operation const_cast
code: no.
Sources of logical errors: the program can change an immutable object. Sometimes this can lead to a segmentation error , sometimes the subroutine may not expect that the memory that it provided for reading has suddenly changed.
For example, consider the code of the dynamic library .
#include <string> // string
using namespace std ;
namespace
{
string s = "Wikipedia" ; // Global variable
// string :: c_str () method returns a const char * type pointer
}
typedef char * PChar ;
void __declspec ( dllexport ) WINAPI SomeDllFunction ( PChar & rMessage )
{
// convert char const * to char *
rMessage = const_cast < char * > ( s . c_str () );
}
When a library is loaded into the process memory , it creates a new data segment in which global variables are located. The code of the SomeDllFunction ()
function is in the library and, when called, returns a pointer to the hidden member of the global object of the string
class. The const_cast
operation const_cast
used to remove the const
modifier.
Operation reinterpret_cast
Purpose: pun typing - the appointment of a memory cell of another type (not necessarily compatible with this) while preserving the bit representation.
The object returned by expression_from
is treated as an object of type type_to
.
Restrictions on expression_from
: an expression must return a value of an ordinal type (any of the integers, a logical bool
or an enumeration enum
), a pointer, or a link.
type_to
restrictions:
- If
expression_from
returns a value of the ordinal type or a pointer, thetype_to
type can be an ordinal type or a pointer. - If
expression_from
returns a reference, thetype_to
type must be a reference.
Whether the operation reinterpret_cast
code: no.
Sources of logical errors. The object returned by expression_from
may not be of type type_to
. There is no way to verify this, the programmer assumes all responsibility for the correctness of the conversion.
Consider examples.
// Returns true if the number x is finite.
// Returns false if the number x is ∞ or NaN.
bool isfinite ( double const x )
{
// convert double const -> uint64_t const &
uint64_t const & y = reinterpret_cast < uint64_t const & > ( x );
return ( ( y & UINT64_C ( 0x7FF0000000000000000 ) ) ! = UINT64_C ( 0x7FF0000000000000 ) );
}
// attempt to get the address of the temporary value
long const & y = reinterpret_cast < long const & > ( x + 5.0 );
// error: the expression x + 5.0 is not a link
See also
- Dynamic cast
- Dynamic Data Type Identification (RTTI)
- Data typing
- Pun typing
Notes
- ↑ cppreference.com. Implicit conversions .
Links
- Robert C. Seacord PINT02-C. Understand integer conversion rules (eng.) , Cert.org