Eroxl's Notes
Switch Statement

A switch statement is a multi-way branch control flow construct that selects one of many code blocks to execute based on the value of an expression. Switch statements provide a more readable and potentially more efficient alternative to long chains of if-else statements.

Syntax in C

switch (expression) {
    case constant1:
        // code block 1
        break;
    case constant2:
        // code block 2
        break;
    default:
        // default code block
        break;
}

Restrictions

Switch statements have specific restrictions that enable efficient implementation:

  • Case labels must be constants: Values must be known at compile time
  • Cardinal types only: Case values must be integers or characters (until Java 1.7, which added strings)
  • Equality comparison: Only tests equality, not ranges or complex conditions
  • Single expression: All cases test the same expression

These restrictions allow the compiler to implement switches using jump tables for efficient O(1) branching.

Implementation Strategies

If-Else Chain

For sparse cases or few options, the compiler uses sequential comparisons:

if (i == 20) {
    j = 10;
} else if (i == 21) {
    j = 11;
} else if (i == 42) {
    j = 12;
} else {
    j = 14;
}

Jump Table

For dense cases, the compiler uses a jump table:

// Original switch
switch (i) {
    case 20: j = 10; break;
    case 21: j = 11; break;
    case 22: j = 12; break;
    default: j = 14; break;
}

// Equivalent with jump table
void *jt[3] = { &&L20, &&L21, &&L22 };
if (i < 20 || i > 22) goto DEFAULT;
goto *jt[i - 20];

L20: j = 10; goto CONT;
L21: j = 11; goto CONT;
L22: j = 12; goto CONT;
DEFAULT: j = 14;
CONT:

Assembly Implementation

In SM213 Assembly, jump tables enable efficient switches:

    ld $i, r0           # r0 = &i
    ld (r0), r0         # r0 = i
    
    # Check bounds: if i < 20 or i > 22, goto default
    ld $-20, r1
    add r0, r1          # r1 = i - 20
    ld $0, r2
    bgt r2, r1          # if r1 < 0 (i < 20), goto default
    ld $3, r2
    bgt r1, r2          # if r1 > 2 (i > 22), goto default
    
    # Jump through table
    ld $jmptable, r2
    j *(r2, r1, 4)      # jmptable[i - 20]

case20:
    ld $10, r1
    br done
case21:
    ld $11, r1
    br done
case22:
    ld $12, r1
    br done
default:
    ld $14, r1
    br done

done:
    ld $j, r0
    st r1, (r0)

jmptable:
    .long case20
    .long case21
    .long case22

Compiler Optimization

The compiler chooses the implementation strategy based on:

Cases Strategy Reason
Sparse (large gaps) If-else chain Jump table would waste memory
Few cases (<4-5) If-else chain Simpler, similar performance
Dense (small gaps) Jump table O(1) lookup, worth the space
Large range If-else chain Jump table too large

Fall-through Behavior

Without break, execution continues to the next case:

switch (i) {
    case 1:
        printf("One ");
        // falls through
    case 2:
        printf("or Two\n");
        break;
}

This is rarely desired and often causes bugs, which is why compilers warn about missing break statements.