Branching
Branching statements select which path of a program executes. Use if and else for boolean conditions, or switch to match integer and enum values.
if
An if statement executes its body when the condition evaluates to true. Conditions must have type bool.
if (temperature > 30)
{
StartCooling();
}
else
An optional else branch executes when the preceding if condition is false.
if (temperature > 30)
{
StartCooling();
}
else
{
KeepRunning();
}
Chained conditions
Place another if after else to test several conditions in order. The first matching branch runs.
if (health == 0)
{
Stop();
}
else if (health < 25)
{
Warn();
}
else
{
Continue();
}
switch, case and default
A switch evaluates an integer or enum value once and selects a body by matching a constant case label.
Each case names a constant value. The optional default body runs when no case matches. Without a match or a default, execution continues after the switch.
int Classify(int value)
{
switch (value)
{
case 0:
return 10;
case 1:
return 20;
default:
return 30;
}
}
The operand must be an integer or enum. Boolean, floating-point, pointer, struct and array operands are not supported.
Switch exits and shared bodies
Multiple consecutive case labels with no statements between them may share the same case body. This does not count as implicit fallthrough: every label enters the same body.
int Group(int value)
{
int result;
switch (value)
{
case 1:
case 2:
case 3:
result = 10;
break;
default:
result = 0;
break;
}
return result;
}
break exits the nearest enclosing loop or switch. A continue inside a switch is valid only when there is an enclosing loop; it continues that loop, not the switch.
Each case body has its own local scope. The compiler tracks assignments across switch exits: in this example every path assigns result before the final return.
A shared body may also return directly:
void SharedReturn(int value)
{
switch (value)
{
case 1:
case 2:
return;
default:
break;
}
}
No implicit fallthrough after code
Once a case body contains reachable executable statements, control must terminate explicitly before another case or default label is reached. Every reachable path must end explicitly, for example with break, return or a valid continue.
switch (value)
{
case 1:
HandleA();
// Compile error: this body can reach the next label.
case 2:
HandleB();
break;
}
The call to HandleA() makes this a separate executable body, not an empty label in a group. Add an explicit exit before case 2, or group the labels before a shared body if they should perform the same work. There is no fallthrough keyword.
Switching on an enum
Labels for an enum operand must have that same enum type. An integer with the same numeric value is not an implicit substitute.
enum State { Idle, Running, Stopped }
int IsActive(State state)
{
switch (state)
{
case State.Running:
return 1;
default:
return 0;
}
}
Constant labels and diagnostics
Case labels may use literals, enum members, module constants, struct constants and local const declarations. Runtime variables and ordinary function calls are not constant labels. Integer labels must fit the operand's integer type.
Two labels with the same evaluated value are an error, even if their expressions or enum member names differ. Only one default is allowed.
Layout queries and native integer casts are evaluated for the selected ABI before emission. Two labels can collide on a 32-bit target while remaining distinct on a 64-bit target. See target-dependent constant evaluation.