Foundations · Module 2 · Lesson 1 of 10
Conditions and Branches: if, else and switch
See how if, else and switch are compiled into comparisons and jumps, trace which blocks run and which are skipped, and learn the classic mistakes: stray semicolons, missing break and assignment in a condition.
By the end you can
- Trace which block of an if-else chain runs for a given value, and which blocks are skipped
- Explain how a condition becomes a comparison followed by a conditional jump
- Predict the output of a switch statement with and without break
- Spot the classic mistakes: assignment in a condition, a stray semicolon and missing braces
Builds on Types Decide What Bits Mean.
01 · A question first
A program never changes direction on its own, so how does it choose between two blocks of code? The CPU has no idea what an if statement is. What does it actually execute, and why can the very same code run several times faster on sorted data than on random data?
Make a guess, then step through the trace below to check it.
02 · Watch it run
int score = 72;char grade = 'C';if (score >= 90) { grade = 'A';} else if (score >= 60) { grade = 'B';}- block 0score >= 90
- block 1grade = A
- block 2score >= 60
- block 3grade = B
- block 4grade: C
Compiled code is a list of blocks laid out in order. The CPU runs them from top to bottom unless a jump sends it elsewhere. Here score is 72 and grade starts as C. The first four cells are the test and block for A, then the test and block for B, and the last cell is grade.
Machine work: score is 72; the program counter is about to reach the first comparison
03 · The idea
Start with the problem
Until now every program ran its statements in order, once. Real programs have to choose: show an error or a result, assign a grade, take one of several actions depending on a command. The language needs a way to run some code only when a condition holds.
int score = 72;
char grade = 'C';
if (score >= 90) {
grade = 'A';
} else if (score >= 60) {
grade = 'B';
}Here grade ends up as 'B'. Reading that is easy for a person. The interesting question is what the machine does, because the CPU has no idea what an if is. It can only execute one instruction after another, and occasionally jump to a different place.
How the idea works
Conditions. An if takes a condition in parentheses. The comparison operators ==, !=, <, <=, > and >= produce a bool, which is true or false. Numbers convert to bool too: 0 is false and every other value is true, so if (count) means if (count != 0).
The chain. The else part attaches a block that runs when the condition was false. else if is not a separate keyword: it is an else whose body happens to be another if statement. That is why chains can be as long as you like, and why order matters. Conditions are tested from the top, the first true one runs its block, and the rest are never evaluated.
What the compiler produces. The trace shows the machine's view. A condition becomes a comparison, an instruction that sets a few bits in the CPU's flags register, followed by a conditional jump, an instruction that either continues with the next instruction or jumps elsewhere depending on those flags. The compiler lays the blocks out in order and aims each jump at the code that should run when the condition is false. When the first test fails, the jump skips the whole block for A (step 2). When the second succeeds, no jump is taken and execution falls into the next block (step 3). When a block is followed by more branches, the compiler also adds an unconditional jump at its end that skips the rest, which is how exactly one path runs (step 5).
The switch statement. When one value is compared against many constants, switch is clearer. This example assumes the three functions exist:
switch (command) {
case 'a': addItem(); break;
case 'd': deleteItem(); break;
default: showHelp();
}The value must be an integer-like type such as int, char or an enumeration, but not a std::string. Execution jumps to the matching case and then keeps running through the following cases until it meets a break or the end of the switch. This is called fall-through. It is sometimes wanted, and C++17's [[fallthrough]]; marks it as intentional. The default label runs when nothing matches.
Other forms. The conditional expression condition ? a : b produces one of two values, as in int larger = (x > y) ? x : y;. Since C++17 an if can declare a variable that exists only inside the statement: if (int n = readCount(); n > 0).
Why it is correct
Structured code is a promise about control flow: each block has one entry and one exit, and the compiler preserves that promise by translating the structure into jumps. A comparison produces a result that the very next instruction consumes, so decisions never depend on hidden state. Because else if is nesting, the rule that the first true condition wins needs no special mechanism, only the order of the code. It also matters that the language guarantees each condition in a chain is evaluated only if every earlier one was false, since evaluating a condition can have side effects, such as calling a function.
For switch, the compiler chooses a strategy. A few cases become the same compare-and-jump chain. Many dense cases, such as the values 0 to 20, can become a jump table, an array of addresses indexed by the value, so any case is reached with a single indirect jump.
What it costs
A correct prediction is nearly free. Modern CPUs do not wait for a comparison to finish. They guess which way each branch will go and start executing along the guess. When the guess is right, the branch costs about one cycle. When it is wrong, the CPU throws away the speculative work, and a typical misprediction costs about 15 to 20 cycles.
Predictable data is faster. A loop that tests every element of a large array can run several times faster when the array is sorted, with identical code, because the outcomes then come in long runs of the same answer and the predictor stays right. Compilers sometimes replace a branch with a branchless conditional move to avoid the problem.
Chains and tables. A long if and else if chain makes up to one comparison per condition in the worst case, while a switch with many dense cases uses a jump table and costs the same for every value. In a chain, put the most common case first.
Pitfalls and variations
Assignment in a condition. if (x = 5) assigns 5 and is always true. The -Wall flag warns about it.
The stray semicolon. if (n > 0); ends the if with an empty body, and the block on the next line then runs unconditionally. The -Wextra flag warns about an empty body.
Missing braces. An if without braces controls only the next statement, so a second line added under it later does not become part of the condition, even though the indentation suggests it does. A well-known 2014 security bug in Apple's TLS code came from a duplicated line under an if that had no braces. Use braces every time.
The forgotten break. A missing break runs the next case as well. The -Wimplicit-fallthrough warning, which -Wextra includes, catches it.
Order in the chain. Testing score >= 60 before score >= 90 makes the second test unreachable, and a 95 receives the B. Put the most specific condition first.
Comparing floating-point values. == on double values is fragile for the reason lesson 4 gave. Compare with a tolerance.
Variations. The statement if constexpr, from C++17, decides at compile time, which a later module uses with templates. C++20 adds the attributes [[likely]] and [[unlikely]], which hint to the compiler which branch is common.
Where it is used
Every program: parsing commands, handling errors, validating input like the retry loop in module 1. Operating system kernels, game loops and interpreters use large switch statements to dispatch on a code, and a virtual machine's main loop is often a switch on the next instruction.
The next lesson, "Boolean Logic and Short-Circuit Evaluation", combines conditions with &&, || and !, and shows why the right-hand side of an && sometimes never runs.
04 · Prove it
Question 1 of 4 · answer from memory
With `int score = 95;`, the chain from the trace tests `score >= 90` first and `else if (score >= 60)` second. What happens?
05 · Practice
Asked in interviews
Something wrong with this lesson? Report a problem