Not that it matters much for such a small number of cases but switch
is in fact faster for integers: it can be, and often is, implemented as a jump table instead of a series of
conditional checks.
As a comparison up the number of different cases to 10:
enum SQLErrorCode{
CODE0 = 0,
CODE1 = 1,
CODE2 = 2,
CODE3 = 3,
CODE4 = 4,
CODE5 = 5,
CODE6 = 6,
CODE7 = 7,
CODE8 = 8,
CODE9 = 9
};
enum SQLErrorCode getErrorCode();
void run()
{
int error = getErrorCode();
#ifdef CASE1
if((error == CODE0) ||
(error == CODE1) ||
(error == CODE2) ||
(error == CODE3) ||
(error == CODE4) ||
(error == CODE5) ||
(error == CODE6) ||
(error == CODE7) ||
(error == CODE8) ||
(error == CODE9) ||
(error < 0))
callFunction1();
else
callFunction2();
#endif
#ifdef CASE2
switch(error)
{
case CODE0:
callFunction1();
break;
case CODE1:
callFunction1();
break;
case CODE2:
callFunction1();
break;
case CODE3:
callFunction1();
break;
case CODE4:
callFunction1();
break;
case CODE5:
callFunction1();
break;
case CODE6:
callFunction1();
break;
case CODE7:
callFunction1();
break;
case CODE8:
callFunction1();
break;
case CODE9:
callFunction1();
break;
default:
callFunction2();
break;
}
#endif
}
Now look at the assembly generated by doing the first case vs. the second, when built on Linux using GCC.
If you look at the assembly you ll see a significant difference (for larger statements): the series of ||
s (or if
/else
if you do it that way) is a series of branches taken one at a time. The switch
turns into a big table: it takes up more code but can mean that it can be handled in one jump.
(Incidentally, we are talking about C here right? Not C#? The code you have won't compile: in C enumerators don't use the enumeration name as a prefix. So it's PARTIAL_OK
without the SQLErrorCode.
)
Code 1: cc -DCASE1 -s switch.s switch.c
.file "1241256.c"
.text
.globl run
.type run, @function
run:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
call getErrorCode
movl %eax, -4(%ebp)
cmpl $0, -4(%ebp)
je .L2
cmpl $1, -4(%ebp)
je .L2
cmpl $2, -4(%ebp)
je .L2
cmpl $3, -4(%ebp)
je .L2
cmpl $4, -4(%ebp)
je .L2
cmpl $5, -4(%ebp)
je .L2
cmpl $6, -4(%ebp)
je .L2
cmpl $7, -4(%ebp)
je .L2
cmpl $8, -4(%ebp)
je .L2
cmpl $9, -4(%ebp)
je .L2
cmpl $0, -4(%ebp)
jns .L13
.L2:
call callFunction1
jmp .L15
.L13:
call callFunction2
.L15:
leave
ret
.size run, .-run
.ident "GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"
.section .note.GNU-stack,"",@progbits
Code 2: cc -DCASE2 -s switch.s switch.c
.text
.globl run
.type run, @function
run:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
call getErrorCode
movl %eax, -4(%ebp)
cmpl $9, -4(%ebp)
ja .L2
movl -4(%ebp), %eax
sall $2, %eax
movl .L13(%eax), %eax
jmp *%eax
.section .rodata
.align 4
.align 4
.L13:
.long .L3
.long .L4
.long .L5
.long .L6
.long .L7
.long .L8
.long .L9
.long .L10
.long .L11
.long .L12
.text
.L3:
call callFunction1
jmp .L15
.L4:
call callFunction1
jmp .L15
.L5:
call callFunction1
jmp .L15
.L6:
call callFunction1
jmp .L15
.L7:
call callFunction1
jmp .L15
.L8:
call callFunction1
jmp .L15
.L9:
call callFunction1
jmp .L15
.L10:
call callFunction1
jmp .L15
.L11:
call callFunction1
jmp .L15
.L12:
call callFunction1
jmp .L15
.L2:
call callFunction2
.L15:
leave
ret
.size run, .-run
.ident "GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"
.section .note.GNU-stack,"",@progbits