if else代码块...还是一个如果有多个OR(||)条件?在C.

时间:2013-05-20 19:49:37

标签: c string performance if-statement

我在C中编写了一个小文本匹配程序,它基本上检查某些字符串中是否存在少量字符(以char数组的形式)。它现在正在工作,我有一个像这样的代码块:

if (c == 'A') return 1;
else if (c == 'B') return 1;
else if (c == 'C') return 1;
....
....
else if (c == 'Z') return 1;
else return 0;

上面的块是否更快?或者这会更快?

if (c == 'A' || c == 'B' || c == 'C' ||....|| c == 'Z') return 1;
else return 0;

快速我的意思是字面上很快,即如果我从程序开始直到结束运行一个简单的计时器,这可能会缩短执行时间?

6 个答案:

答案 0 :(得分:7)

我建议您执行以下操作:

#include <ctype.h>

...

return isupper(c)

而不是手动检查所有这些。标准C库函数速度相当快,因此性能应该是可以接受的。

答案 1 :(得分:5)

经验法则是,如果您不确定它是否真的值得,您不应该担心这些小的性能问题。

在任何情况下,如果你想检查任何AZ字母,那么这个(请注意,这假设所用字符的编码不应该在AZ之间有任何外部符号{1}}或者这不起作用)

if (c >= 'A' && c <= 'Z')

肯定是一种更简单的方法。

不要忘记,对于表达式值长的if if else,您甚至可以使用switch语句:

switch (exp) {
  case 'A':
  case 'B':
  case 'C':
  ...
    return 1;
  default: return 0;
}

在某些情况下,switch可能稍微快一些,因为根据编译器,它可以使用查找表,但我们实际上是在谈论微秒。

为了完整起见,C标准库有两种方法isupperisaplha可以使用:

if (isupper(c)) // c is an alphabetic uppercase character

答案 2 :(得分:4)

优化编译器同样会处理这两种形式。

将这种微优化保留给编译器。同样重要的是源代码的可读性。

(当然你需要为GCC -e.g.最近的GCC 4.8启用优化 - 你将使用gcc -O2进行编译。

你真的需要确定基准(因为大量其他因素也很重要:特别是缓存局部性)什么是最好的。您甚至可以使用一些更奇特的算法(例如,在E之类的罕见字母之前测试更频繁的字母,例如Z。查找search trees了解更多信息。

在生成的汇编代码中查找实例(使用gcc -O2 -fverbose-asm -S获取它)或查看内部表示,例如使用the MELT probe(或将-fdump-tree-all - 许多转储文件传递给您 - gcc)。

使用GCC扩展程序,对于您的具体示例,您甚至可以像这样编码case ranges

 switch (c) {
    case 'A' ... 'Z': return 1;
    default: return 0;
 }

上述案例范围表明字符编码是ASCII的超集。它不适用于EBCDIC

实际上,交换机优化很复杂。见this paper等......

实际上,您希望使用<ctype.h>中的isalpha(3)(在C99标准中)。

测试什么是字母并不是那么简单:éИ是后者吗?对我来说它是一个(它们都是元音,在UTF8中都需要多个字节)

对常见的UTF-8编码要谨慎:有些字母(特别是非英语或字母表)用几个字节编码。看,例如在Glib Unicode Manipulation函数。

答案 3 :(得分:0)

如果您有更多条件,交换机块会更好:

switch(c) {
   case 'A':
   case 'B':
   // (...)
   case 'Z': return 1;
   default: return 0;
}

答案 4 :(得分:0)

如果没有进入编译器优化,程序集生成和更好的算法的范围,其他海报遗漏的是单个if多个测试用例和多个OR(||)将在第一次匹配后短路。实际上,第一个和第二个代码片段将在速度方面产生等效的ASM。

答案 5 :(得分:0)

正如其他提到的,没有什么不同。在cmp条件下将生成相同数量的if指令(不考虑编译器的任何优化)

修改

考虑这个 C 函数:

int is_letter2(int c)
{
  if(c == 'A') return 1;
  else if(c == 'B') return 1;
  else if(c == 'C') return 1;
  else if(c == 'D') return 1;
  else if(c == 'E') return 1;
  else if(c == 'F') return 1;
  else if(c == 'G') return 1;
  else if(c == 'H') return 1;
  else if(c == 'I') return 1;
  else if(c == 'J') return 1;
  else if(c == 'K') return 1;
  else if(c == 'L') return 1;
  else if(c == 'M') return 1;
  else if(c == 'N') return 1;
  else if(c == 'O') return 1;
  else if(c == 'P') return 1;
  else if(c == 'Q') return 1;
  else if(c == 'R') return 1;
  else if(c == 'S') return 1;
  else if(c == 'T') return 1;
  else if(c == 'U') return 1;
  else if(c == 'V') return 1;
  else if(c == 'W') return 1;
  else if(c == 'X') return 1;
  else if(c == 'Y') return 1;
  else if(c == 'Z') return 1;
  else return 0;
}

int is_letter(int c)
{
  if(c == 'A' ||c == 'B' ||c == 'C' ||c == 'D' ||c == 'E' ||c == 'F' ||c == 'G' ||c == 'H' ||c == 'I' ||c == 'J' ||c == 'K' ||c == 'L' ||c == 'M' ||c == 'N' ||c == 'O' ||c == 'P' ||c == 'Q' ||c == 'R' ||c == 'S' ||c == 'T' ||c == 'U' ||c == 'V' ||c == 'W' ||c == 'X' ||c == 'Y' ||c == 'Z')
    return 1;
 else return 0;
}

汇编输出:几乎是相同。退房:

is_letter2:
.LFB1:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    cmpl    $65, 8(%ebp)
    jne .L3
    movl    $1, %eax
    jmp .L4
.L3:
    cmpl    $66, 8(%ebp)
    jne .L5
    movl    $1, %eax
    jmp .L4
.L5:
    cmpl    $67, 8(%ebp)
    jne .L6
    movl    $1, %eax
    jmp .L4
.L6:
    cmpl    $68, 8(%ebp)
    jne .L7
    movl    $1, %eax
    jmp .L4
.L7:
    cmpl    $69, 8(%ebp)
    jne .L8
    movl    $1, %eax
    jmp .L4
.L8:
    cmpl    $70, 8(%ebp)
    jne .L9
    movl    $1, %eax
    jmp .L4
.L9:
    cmpl    $71, 8(%ebp)
    jne .L10
    movl    $1, %eax
    jmp .L4
.L10:
    cmpl    $72, 8(%ebp)
    jne .L11
    movl    $1, %eax
    jmp .L4
.L11:
    cmpl    $73, 8(%ebp)
    jne .L12
    movl    $1, %eax
    jmp .L4
.L12:
    cmpl    $74, 8(%ebp)
    jne .L13
    movl    $1, %eax
    jmp .L4
.L13:
    cmpl    $75, 8(%ebp)
    jne .L14
    movl    $1, %eax
    jmp .L4
.L14:
    cmpl    $76, 8(%ebp)
    jne .L15
    movl    $1, %eax
    jmp .L4
.L15:
    cmpl    $77, 8(%ebp)
    jne .L16
    movl    $1, %eax
    jmp .L4
.L16:
    cmpl    $78, 8(%ebp)
    jne .L17
    movl    $1, %eax
    jmp .L4
.L17:
    cmpl    $79, 8(%ebp)
    jne .L18
    movl    $1, %eax
    jmp .L4
.L18:
    cmpl    $80, 8(%ebp)
    jne .L19
    movl    $1, %eax
    jmp .L4
.L19:
    cmpl    $81, 8(%ebp)
    jne .L20
    movl    $1, %eax
    jmp .L4
.L20:
    cmpl    $82, 8(%ebp)
    jne .L21
    movl    $1, %eax
    jmp .L4
.L21:
    cmpl    $83, 8(%ebp)
    jne .L22
    movl    $1, %eax
    jmp .L4
.L22:
    cmpl    $84, 8(%ebp)
    jne .L23
    movl    $1, %eax
    jmp .L4
.L23:
    cmpl    $85, 8(%ebp)
    jne .L24
    movl    $1, %eax
    jmp .L4
.L24:
    cmpl    $86, 8(%ebp)
    jne .L25
    movl    $1, %eax
    jmp .L4
.L25:
    cmpl    $87, 8(%ebp)
    jne .L26
    movl    $1, %eax
    jmp .L4
.L26:
    cmpl    $88, 8(%ebp)
    jne .L27
    movl    $1, %eax
    jmp .L4
.L27:
    cmpl    $89, 8(%ebp)
    jne .L28
    movl    $1, %eax
    jmp .L4
.L28:
    cmpl    $90, 8(%ebp)
    jne .L29
    movl    $1, %eax
    jmp .L4
.L29:
    movl    $0, %eax
.L4:
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc
.LFE1:
    .size   is_letter2, .-is_letter2
    .globl  is_letter
    .type   is_letter, @function
is_letter:
.LFB2:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    cmpl    $65, 8(%ebp)
    je  .L31
    cmpl    $66, 8(%ebp)
    je  .L31
    cmpl    $67, 8(%ebp)
    je  .L31
    cmpl    $68, 8(%ebp)
    je  .L31
    cmpl    $69, 8(%ebp)
    je  .L31
    cmpl    $70, 8(%ebp)
    je  .L31
    cmpl    $71, 8(%ebp)
    je  .L31
    cmpl    $72, 8(%ebp)
    je  .L31
    cmpl    $73, 8(%ebp)
    je  .L31
    cmpl    $74, 8(%ebp)
    je  .L31
    cmpl    $75, 8(%ebp)
    je  .L31
    cmpl    $76, 8(%ebp)
    je  .L31
    cmpl    $77, 8(%ebp)
    je  .L31
    cmpl    $78, 8(%ebp)
    je  .L31
    cmpl    $79, 8(%ebp)
    je  .L31
    cmpl    $80, 8(%ebp)
    je  .L31
    cmpl    $81, 8(%ebp)
    je  .L31
    cmpl    $82, 8(%ebp)
    je  .L31
    cmpl    $83, 8(%ebp)
    je  .L31
    cmpl    $84, 8(%ebp)
    je  .L31
    cmpl    $85, 8(%ebp)
    je  .L31
    cmpl    $86, 8(%ebp)
    je  .L31
    cmpl    $87, 8(%ebp)
    je  .L31
    cmpl    $88, 8(%ebp)
    je  .L31
    cmpl    $89, 8(%ebp)
    je  .L31
    cmpl    $90, 8(%ebp)
    jne .L32
.L31:
    movl    $1, %eax
    jmp .L33
.L32:
    movl    $0, %eax
.L33:
    popl    %ebp
    .cfi_def_cfa 4, 4
    .cfi_restore 5
    ret
    .cfi_endproc

在简历中,它是相同的程序。