我在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;
快速我的意思是字面上很快,即如果我从程序开始直到结束运行一个简单的计时器,这可能会缩短执行时间?
答案 0 :(得分:7)
我建议您执行以下操作:
#include <ctype.h>
...
return isupper(c)
而不是手动检查所有这些。标准C库函数速度相当快,因此性能应该是可以接受的。
答案 1 :(得分:5)
经验法则是,如果您不确定它是否真的值得,您不应该担心这些小的性能问题。
在任何情况下,如果你想检查任何AZ字母,那么这个(请注意,这假设所用字符的编码不应该在A
和Z
之间有任何外部符号{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标准库有两种方法isupper
和isaplha
可以使用:
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
在简历中,它是相同的程序。