Explicit type casting

Explicitly converting variables

To explicitly convert a type to an other, we can use the C style notation, which is done by adding, before the value or the variable we want to convert, the type, between parentheses (), we want to convert it to:

int var = -6; unsigned var2 = (unsigned) var;

In the example above, explicitly stating the conversion was not required, but in some cases it is. It is also possible, in C++ only, to use the functional notation which is written by putting the type we want to convert it to, followed by the value or variable we want to convert between parentheses ():

int var = -6; unsigned var2 = unsigned(var);

Note that when we use the functional notation and the type we want to convert to is made of more than 1 word (Example: unsigned long), we have to also put the type between parentheses ():

int var = -6; unsigned long var2 = (unsigned long)(var);

When we print a variable of type char to the console, what is displayed is the ASCII character assigned to the value represented by the variable. What if we want to print its numerical value instead? We can do that by explicitly converting it into an other type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream> int main() { char c = 'a'; // 'a' equals 97. std::cout << c << std::endl; // 'a' is printed in the console. std::cout << (int) c << std::endl; // 97 is printed in the console. std::cout << 'j' << std::endl; // 'j' is written to the console. std::cout << int('j') << std::endl; // 106 is outputted to the console. return 0; }

Casting pointers

Using explicit type casting, we can make a pointer of a certain type points to a variable of a different type. What it the use of that? Look at the example below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream> int main() { char array[4]; unsigned int * ptr = (unsigned int*)array; *ptr = 0; std::cout << int(array[0]) << int(array[1]) << int(array[2]) << int(array[3]) << std::endl; // "0000" is printed in the console. return 0; }

The type char always weights 1 byte. Let us consider the type unsigned int weights 4 bytes and a byte is made of 8 bits. By making the pointer of type unsigned int ptr point to the array of char and assigning the value pointed by it to 0, it stores the number 0, as a variable of type int, a the beginning of array. Since the unsigned int type weights 4 bytes and a byte is made of 8 bits(In that example), 32 bits, with a value of zero, are written in the memory, at the location of the array. That means 4 groups of 8 bits, with the value zero, are stored where the array is. Therefore, all the elements of the array (Which has a size of 4 bytes, so 32 bits in that example) are set to 0. If we had set the value of the elements of the array one by one, it would have taken 4 instructions. In the example above, the four elements of the array are set to 0 in one instruction. It is about 4 times faster.

Pointer of type void

It is possible to define a pointer with the type void. A void pointer can point to any variable without any need to use explicit type casting. However, each time we access the location pointed by it, we must specify, using explicit casting, which type of pointer we want the compiler to assume it is (To tell the compiler how to interpret the content (bytes) at the pointed address).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream> int main() { unsigned char array[8]; void * ptr = array; *(short*)ptr = 0; // The first two elements of array are set to 0. std::cout << int(array[0]) << int(array[1]) << std::endl; ((unsigned short*)ptr)[6] = 65535; // The last two elements of the array are set to 255. /* 65535 in binary: 11111111 11111111b */ std::cout << int(array[6]) << int(array[7]) << std::endl; *(unsigned long long*)ptr = 0; // All the elements of the array are set to 0. std::cout << int(array[0]) << int(array[1]) << int(array[2]) << int(array[3]) << std::endl; std::cout << int(array[4]) << int(array[5]) << int(array[6]) << int(array[7]) << std::endl; return 0; }

In the example above, the type unsigned short is assumed to weight 2 bytes and unsigned long long is assumed to weight 8 bytes.

The explicit cast const_cast

The explicit cast const_cast is a feature of C++. It is used to convert a constant variable into a non-constant variable, or the opposite.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream> void func(int * a) { std::cout << *a << std::endl; } int main() { const int n = 78; func(&n); // Error: n is constant and the function takes a non-constant pointer as argument. return 0; }

We can not give a constant pointer (Address to a constant variable) to a function that takes a non-constant pointer as argument. That can be resolved by converting the pointer to a non-constant pointer using the const_cast explicit type casting. It is coded by writing the keyword const_cast followed by the type to convert to between < and > followed by the variable to convert between parentheses ().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> void func(int * a) { std::cout << *a << std::endl; } int main() { const int n = 78; func(const_cast<int *>(&n)); // 78 is written in the console. return 0; }

Note that variables are declared constant for a reason: To be sure their value stay untouched. Therefore, it is usually not a good idea to convert a constant pointer to a non-constant one. It is, however, good to know it is possible to do it.

Comparing variables of enumeration class type with numbers

Earlier, we saw that we can not directly compare a variable of an enumeration class type with a numerical value (number). It is also true for the elements of an enumeration class. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream> enum class Color{Red, Green, Blue, Yellow, Orange}; int main() { Color color = Color::Blue; if(color == 2) // Error: color can not directly be compared to a number. std::cout << "The variable color equals 1." << std::endl; if(Color::Red == 0) // Error: Color::Red can not directly be compared to a number. std::cout << "The element Color::Red equals 0." << std::endl; return 0; }

It can, however, be done by explicitly casting the variable or element to an unsigned or signed primitive integer type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream> enum class Color{Red, Green, Blue, Yellow, Orange}; int main() { Color color = Color::Blue; if((int)color == 2) // Now it works. std::cout << "The variable color equals 2." << std::endl; if((int)Color::Red == 0) // Now it works. std::cout << "The element Color::Red equals 0." << std::endl; return 0; }

Other explicit type casts

There are, in C++, 3 other explicit type casts (dynamic_cast, static_cast and reinterpret_cast), but they require a good understanding of classes to be understood. We will therefore see what they do and how to use them, later.