---
tags: C, programming, C++
---
# The C/C++ `switch` statement
References and quotes are from [this awesome doc from Microsoft](https://docs.microsoft.com/en-us/cpp/c-language/switch-statement-c?view=msvc-160).
## I'm familiar with `switch` already, so what?
Presumably you're familiar with this specific style of `switch`:
```c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
if( argc != 2)
return 1;
int user_input = atoi(argv[1]);
int ret = 0;
switch( user_input ){
case 1:
printf( "First\n" );
break;
case 2:
printf( "TWO\n" );
break;
case 69:
printf( "Noice\n" );
break;
default:
printf( "Peko...\n" );
ret = 1;
break;
}
return ret;
}
```
Which naturally corresponds to the following equivalent:
```C
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv){
if( argc != 2)
return 1;
int user_input = atoi(argv[1]);
int ret = 0;
if( user_input == 1 ){
printf( "First\n" );
}else if ( user_input == 2 ){
printf( "TWO\n" );
}else if ( user_input == 69 ){
printf( "Noice\n" );
}else{
printf( "Peko...\n" );
ret = 1;
}
return ret;
}
```
So then, why spend time illustrate this?
## `C/C++` syntax is much like `asm`
`switch` and `break` are just like `JAL` with `rd == x0` in RISC-V assembly or `JMP` in x86_64, and the `case` are like the tags in assembly!
> Execution of the `switch` statement body begins at the first statement in or after the matching `labeled-statement`. Execution proceeds until the end of the body, or until a `break` statement transfers control out of the body.
With this understanding, this following code would be less confusing:
```c
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char** argv ){
if( argc != 2 )
exit(1);
int user_input = atoi(argv[1]);
switch(user_input){
case 420:
user_input--;
printf( "marijuanas; user_input = %d\n", user_input );
default:
user_input = 68;
printf( "default; user_input = %d\n", user_input );
case 69:
printf( "Noice(?); break\n" );
break;
}
return 0;
}
```
When `./a.out 69`, we would have:
```
Noice(?); break
```
This spefic case is intuitive to unserstand, but when `x` is `420`:
```
marijuanas; user_input = 419
default; user_input = 68
Noice(?); break
```
And when `x` is any number other than `420` or `69`:
```
default; user_input = 68
Noice(?); break
```
Seems kinda absurd, right? `user_input` is not `69`, but `Noice` is present in output!
This is because what `switch` do is *transfer control to specific tag*
> A `switch` statement causes control to transfer to one `labeled-statement` in its statement body, depending on the value of `expression`.
After the control is transferred to the specific `case`, the expression used in `switch()` and the cases in `switch` body are just *irrelevant*; they only serve as landmarks for the `switch(user_input)` to jump!
Hence, when situation like `user_input == 42069`, when computer sees the `switch`, it would think, "*I got 3 places to jump to; it's not `420`, it's not `69`, so it's `default` to jump to!*" and jumps there. After printing `default; user_input = 68`, the computer just *don't care* if `user_input == 69` as seemly suggested by `case 69`; `case 69` is compiled to be a tag in assembly to jump to, and have *no* semantics when we're not jumping! Since it's just a tag in assembly, computer would just continue the execution like it's not there.
Below is possible corresponding assembly output; comment added with `#` for clarification:
```assembly
.file "switch.c"
.option nopic
.attribute arch, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "marijuanas; user_input = %d\n"
.align 3
.LC1:
.string "default; user_input = %d\n"
.align 3
.LC2:
.string "Noice(?); break"
.section .text.startup,"ax",@progbits
.align 1
.globl main
.type main, @function
main:
addi sp,sp,-16
sd ra,8(sp)
li a5,2
bne a0,a5,.L7
ld a0,8(a1)
call atoi
li a5,69
beq a0,a5,.L3
li a5,420
beq a0,a5,.L8
.L4:
# `default`
# notice the 2 `beq` above
lui a0,%hi(.LC1)
li a1,68
addi a0,a0,%lo(.LC1)
call printf
.L3:
# `case 69`
lui a0,%hi(.LC2)
addi a0,a0,%lo(.LC2)
call puts
ld ra,8(sp)
li a0,0
addi sp,sp,16
jr ra
.L8:
# `case 420`
lui a0,%hi(.LC0)
li a1,419
addi a0,a0,%lo(.LC0)
call printf
j .L4
.L7:
li a0,1
call exit
.size main, .-main
.ident "GCC: (Arch Linux Repositories) 10.2.0"
```
```bash
$ riscv64-elf-gcc --version
riscv64-elf-gcc (Arch Linux Repositories) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ riscv64-elf-gcc -O2 -S -o switch.s switch.c
```