Не то чтобы это имело большое значение для такого небольшого числа случаев, но switch
на самом деле быстрее для целых чисел: его можно и часто реализовывать в виде таблицы переходов вместо серии
условные проверки.
Для сравнения приведу количество разных случаев до 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
}
Теперь рассмотрим сборку, сгенерированную в первом и втором случаях при сборке в Linux с использованием GCC.
Если вы посмотрите на сборку, вы увидите существенную разницу (для более крупных операторов): серия ||
s (или if
/ else
, если вы сделаете это таким образом) - это серия ветвей, взятых один за раз. switch
превращается в большую таблицу: она требует больше кода, но может означать, что она может быть обработана за один переход.
(Кстати, мы говорим о C здесь, верно? Не C #? Код, который вы не будете компилировать: в C перечислители не используют имя перечисления в качестве префикса. Так что PARTIAL_OK
без SQLErrorCode.
) * * тысяча двадцать-один
Код 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
Код 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