优化的strcmp实现

这个function在这里找到。 这是strcmp的一个实现:

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

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

 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定义。

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

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

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

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

我喜欢这段代码:

 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的机器代码更糟(我不知道为什么)。

这个实现可以进一步优化,削减一些比较:

 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 。 返回值的符号是第一个不同字符之间的差异unsigned char ,根据C标准转换为unsigned char

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

  • sizeof(int) == 1 ,返回值应以这种方式计算:

     return (c1 < c2) ? -1 : 1; 

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

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

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