优化的strcmp实现

时间:2013-11-15 15:24:42

标签: c string-comparison strcmp

找到此功能here。它是strcmp的实现:

int strcmp(const char* s1, const char* s2)
{
    while (*s1 && (*s1 == *s2))
        s1++, s2++;
    return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}

我理解除了最后一行之外的所有内容,简而言之,最后一行是怎么回事?

5 个答案:

答案 0 :(得分:5)

return *(const unsigned char*)s1-*(const unsigned char*)s2;

OP:简言之,最后一行是怎么回事?

答:比较第一个潜在的字符串差异。根据规范的要求,chars都被引用为unsigned char。 2被提升为int,并返回差异。


注意:

1返回值的符号(< 0,0,> 0)是最有意义的部分。它是C规范中唯一指定的部分。

2在某些系统charsigned(更常见)。在其他人上,charunsigned。定义最后一次比较的“符号”可以提高可移植性。请注意,fgetc()获得的字符为unsigned char

3除了字符串以\0结尾之外,所使用的字符编码(如ASCII - 最常见)在二进制级别上没有区别。如果2个字符串中不同的第一个char具有值65和97,则第一个字符串将小于第二个字符串,即使字符编码是非ASCII。 OTOH,strcmp("A", "a")将在字符编码为ASCII时返回负数,但可能会为其基础值返回不同字符编码中的正数,并且顺序不由C定义。

答案 1 :(得分:2)

这个实现绝对不是内置strcmp的优化,它只是另一个实现,我相信它最有可能比内置版本更差。

如果比较的值相等,则比较函数应返回0;如果第一个值较小,则返回任何负数;如果第一个值较大,则返回任何正数。这就是最后一行发生的事情。

最后一行的想法是将字符转换为无符号字符,我相信作者的意思是在标准字符之后对非标准字符进行排序(ASCII代码0-127)。

编辑:代码中没有错误,如果s1指向的值小于s2在使用代码的字符前排序标准字符所指向的值,它会返回负值128以上。

答案 2 :(得分:1)

我预先知道这段代码:

int strcmp(const char *str1, const char *str2)
{
    int s1;
    int s2;
    do {
        s1 = *str1++;
        s2 = *str2++;
        if (s1 == 0)
            break;
    } while (s1 == s2);
    return (s1 < s2) ? -1 : (s1 > s2);
}

对于ARMv4,它编译为:

strcmp:
    ldrsb   r3, [r0], #1 ;r3 = *r0++
    ldrsb   r2, [r1], #1 ;r2 = *r1++
    cmp     r3, #0       ;compare r3 and 0
    beq     @1           ;if r3 == 0 goto @1
    cmp     r3, r2       ;compare r3 and r2
    beq     strcmp       ;if r3 == r2 goto strcmp
;loop is ended
@1:
    cmp     r3, r2     ;compare r3 and r2
    blt     @2         ;if r3 < r2 goto @2
    movgt   r0, #1     ;if r3 > r2 r0 = 1
    movle   r0, #0     ;if r3 <= r2 r0 = 0
    bx      lr         ;return r0
@2:
    mov     r0, #-1    ;r0 = -1
    bx      lr         ;return r0

正如您所看到的,循环下只有6条指令,最后只有5条指令。所以复杂度是6 *(strlen + 1)+5。

将(s1 == 0)移动到while条件会导致ARM的机器代码更糟(我不知道为什么)。

答案 3 :(得分:1)

此实施可以进一步优化,削减一些比较:

int strcmp(const char *s1, const char *s2) {
    unsigned char c1, c2;
    while ((c1 = *s1++) == (c2 = *s2++)) {
        if (c1 == '\0')
            return 0;
    }
    return c1 - c2;
}

如果字符串相同并且包括终止空字节,则返回值为0。返回值的符号是第一个不同字符之间的差异符号,根据C标准转换为unsigned char

  • 如果char小于int,除了一些罕见的嵌入式系统外都是如此,可以通过简单的减法计算这个差异,c1和{ {1}}被提升为c2,这种差异可以保证适合int类型的范围。

  • int的系统上,应以这种方式计算返回值:

    sizeof(int) == 1

答案 4 :(得分:0)

strcmp返回哪个字符串大于另一个字符串,而不仅仅是它们是否相等。

最后一行减去第一个不匹配的字符,看哪个更大。如果整个字符串匹配,那么它将是0-0=0,它给出了“相等”的结果。

这个实现并没有得到很好的优化,因为它需要汇编代码和缓存行,负载大小等知识。