switch case programming practice
1 2 3 4 5 6 | enum SQLErrorCode{ OK = 0, PARTIAL_OK = 1, SOMEWHAT_OK = 2, NOT_OK = 3, }; |
代码1:
1 2 3 4 5 6 7 8 | int error = getErrorCode(); if((error == SQLErrorCode.PARTIAL_OK) || (error == SQLErrorCode.SOMEWHAT_OK) || (error == SQLErrorCode.NOT_OK) || (error < 0)) callFunction1(); else callFunction2(); |
代码2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | switch(error){ case SQLErrorCode.PARTIAL_OK: callFunction1(); break; case SQLErrorCode.SOMEWHAT_OK: callFunction1(); break; case SQLErrorCode.NOT_OK: callFunction1(); break; default: callFunction2(); break; } |
我更喜欢哪种方法。就性能而言,不应该有太大的差别。如何处理开关柜的误差小于0的情况。
编辑:乔尔的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 | switch(error) { case SQLErrorCode.PARTIAL_OK: case SQLErrorCode.SOMEWHAT_OK: case SQLErrorCode.NOT_OK: callFunction1(); break; case SQLErrorCode.OK: callFunction2(); break; default: // error < 0 is handled callFunction1(); break; } |
q.处理误差<0。如果我必须处理其他不属于这里任何情况(包括默认情况)的错误号码。
在不表达对哪一个最好的偏好的情况下,还有另一种可能性:
1 2 3 4 5 6 7 8 9 10 | switch(error){ case SQLErrorCode.PARTIAL_OK: case SQLErrorCode.SOMEWHAT_OK: case SQLErrorCode.NOT_OK: callFunction1(); break; default: callFunction2(); break; } |
对于这样一小部分情况来说,这并不重要,但是对于整数来说,
作为比较,将不同案例的数量增加到10个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | 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 |
}
现在看看在使用gcc的Linux上构建的第一种情况与第二种情况所生成的程序集。
如果你看一下这个组件,你会发现一个显著的区别(对于更大的声明):EDOCX1系列(或EDOCX1系列〔7〕/EDOCX1系列〔8〕,如果你这样做的话)是一次取一个分支。
(顺便说一下,我们在这里谈论的是C,对吗?不是C?您将无法编译的代码:在C枚举器中,不使用枚举名称作为前缀。所以它是
代码1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | .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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | .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 |
为什么不。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | switch(error) { case SQLErrorCode.PARTIAL_OK: case SQLErrorCode.SOMEWHAT_OK: case SQLErrorCode.NOT_OK: callFunction1(); break; case SQLErrorCode.OK: callFunction2(); break; default: if (error < 0) callFunction1(); else callFunction2(); break; } |
写起来比开关容易,读起来比中频容易。但它仍然处理小于0的错误。
编辑:
理查德提出了一个很好的观点。我已经编辑过处理已知范围之外的正负错误。
您还可以编写一个函数来确定什么是OK错误或NotOK错误代码:
1 2 3 4 | bool isOK(int code) { return code == SQLErrorCode.OK; } |
你的代码可能会变成:
1 2 3 4 5 6 7 8 | if (isOk(getErrorCode())) { callFunction2; } else { callFunction1; } |
假设
1 2 3 4 5 | int error = getErrorCode(); if (error == SQLErrorCode.OK) callFunction2(); // Good path else callFunction1(); // Error / not good enough path |
显然,如果您的代码需要在
每当你有多种方法获得相同的效果,你就会引起混乱。因为,在交换机版本中,
在本例中,我将使用一个if语句,因为这个想法是使用一个或另一个函数。
我有一阵子没碰过C了,但它是不是掉下来了?所以你可以这样写第二个查克…
1 2 3 4 5 6 7 8 9 | switch(error){ case SQLErrorCode.PARTIAL_OK: case SQLErrorCode.SOMEWHAT_OK: case SQLErrorCode.NOT_OK: callFunction1(); break; default: callFunction2(); break; |
}