2

我正在用 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;

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

4

6 回答 6

7

我建议执行以下操作:

#include <ctype.h>

...

return isupper(c)

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

于 2013-05-20T20:06:56.983 回答
5

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

在任何情况下,如果您想检查任何 AZ 字母,那么这个(请注意,这对所使用的字符的编码做出了假设,在 and 之间不应有任何外部符号AZ否则这将不起作用)

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

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

不要忘记,如果 else 链接表达式值很长,您甚至可以使用switch语句:

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

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

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

if (isupper(c)) // c is an alphabetic uppercase character
于 2013-05-20T19:52:47.903 回答
4

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

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

(当然您需要启用优化,对于GCC - 例如最近的 GCC 4.8- 您将使用 编译gcc -O2)。

而且您确实需要进行基准测试以确定(因为大量其他因素也很重要:特别是缓存位置)什么是最好的。你甚至可以使用一些更花哨的算法(例如E,在罕见的字母之前测试更频繁的字母,比如Z)。寻找更多的搜索树

例如查看生成的汇编代码(用于gcc -O2 -fverbose-asm -S获取它)或查看内部表示,例如使用MELT 探针(或传递-fdump-tree-all- 给你许多转储文件 - 到gcc)。

使用 GCC 扩展,对于您的具体示例,您甚至可以对大小写范围进行编码,如下所示:

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

上述情况范围假定字符编码是ASCII的超集。它不适用于EBCDIC

实际上,开关优化很复杂。见这篇论文等......

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

测试什么是字母并不是那么简单:是适合你é还是И后者?对我来说是一个(它们都是元音,都需要 UTF8 中的一个以上字节)

请注意常见的UTF-8编码:一些字母(尤其是来自非英语语言或字母表的字母)使用多个字节进行编码。看看例如Glib Unicode 操作函数。

于 2013-05-20T19:52:33.513 回答
0

如果你有更多的条件,一个 switch 块会更好:

switch(c) {
   case 'A':
   case 'B':
   // (...)
   case 'Z': return 1;
   default: return 0;
}
于 2013-05-20T19:53:06.963 回答
0

在不涉及编译器优化、程序集生成和更好的算法的范围内,其他发帖人错过的是具有多个测试用例和多个 OR ( ||) 的单个 if 在第一次匹配后会短路。实际上,第一段和第二段代码将在速度方面生成等效的 ASM。

于 2013-05-20T20:22:21.343 回答
-1

正如其他提到的,没有什么不同。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

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

于 2013-05-20T20:24:58.723 回答