Home

#7 Casting

Casting

Casting shows up early in programming because sooner or later you’ll run into mathematical expressions that don’t behave the way you expect. When that happens, two things usually need to be checked:

  1. The order of operations
  2. The types involved in the calculation

Integer math in particular can produce surprising results, especially with division or expressions that combine division with other operators.

For example:

When the default behavior isn’t what you want, you often need to force the calculation into the correct form — usually by casting one or more operands to a different type.

Casting lets you take control of the expression so the result matches your intention rather than the compiler’s default rules.

In C++ there we typically use the following to cast (force) a value to a specific type.

static_cast<type_to_convert_to>(expression)

Example

// Ex05 - Simple cast example

import std;

int main()
{
  double metalSpringSize = {34.65};
  int metalSpringIntSize = static_cast<int>(metalSpringSize);

  std::println("Integer spring size: {}.", static_cast<int>(metalSpringSize));
  std::println("Integer spring size: {}.", metalSpringIntSize);

  return 0;
}

static_cast is a built‑in C++ cast operator, not a function.
It uses function‑like syntax, but the compiler treats it as a special language construct.

🧠 Key differences from a real function

The compiler enforces rules about what conversions are allowed.

No function is called — the compiler rewrites the expression at compile time.

No runtime cost — it doesn’t generate a function call instruction.

The angle‑bracket type is not a template parameter — it’s part of the cast syntax.

As we progress through later lessons, the full power of static_cast will become clearer. For now, just understand that using static_cast tells the compiler:

“I know what I’m doing — perform this conversion exactly as written.”

Without this explicit cast, the compiler may issue warnings or even errors depending on the situation.

⚠️ Loss of Precision

For Example:

// Ex06 - Loss of percision

import std;

int main()
{
  double metalSpringSize = {34.65};
  int metalSpringIntSize = metalSpringSize;

  std::println("Integer spring size: {}.", metalSpringIntSize);

  return 0;
}

The above will produce the following warning.

Assigning a double to an int causes a narrowing conversion.
The fractional part is discarded, not rounded.

Output: Integer sprint size: 34.

The compiler will warn you about this because it may not be what you intended. The program still compiles, but the warning is a hint that you should review the code.

Treating warnings as errors

To prevent accidental precision loss (and many other issues), you can force the compiler to treat all warnings as errors by adding /WX:

@echo on

mkdir .\build
pushd .\build

del /Q *.* 

cl /std:c++latest /EHsc /nologo /W4 /WX /c "%VCToolsInstallDir%\modules\std.ixx" "%VCToolsInstallDir%\modules\std.compat.ixx" ../src/main.cpp

cl /EHsc /std:c++latest ../build/main.obj ../build/std.obj /Fe:main.exe

popd

It is good practice to clear all warnings before moving code to production.

C Style Cast

Before the introduction of static_cast there was what is commonly referred to as the C Style Cast.

(convert_to)expression

Example from our Ex05 would be like this.

// Ex07 - C Style Cast

import std;

int main()
{
  double metalSpringSize = {34.65};
  int metalSpringIntSize = (int)metalSpringSize;

  std::println("Integer spring size: {}.", (int)metalSpringSize);
  std::println("Integer spring size: {}.", metalSpringIntSize);

  return 0;
}

The output is identical to the static_cast example, but C‑style casts are considered less safe because they allow many different types of conversions — some of which static_cast would reject.

For this reason, modern C++ code strongly prefers static_cast.