找到此功能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;
}
我理解除了最后一行之外的所有内容,简而言之,最后一行是怎么回事?
答案 0 :(得分:5)
return *(const unsigned char*)s1-*(const unsigned char*)s2;
OP:简言之,最后一行是怎么回事?
答:比较第一个潜在的字符串差异。根据规范的要求,chars
都被引用为unsigned char
。 2被提升为int
,并返回差异。
注意:
1返回值的符号(< 0,0,> 0)是最有意义的部分。它是C规范中唯一指定的部分。
2在某些系统char
上signed
(更常见)。在其他人上,char
是unsigned
。定义最后一次比较的“符号”可以提高可移植性。请注意,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
,它给出了“相等”的结果。
这个实现并没有得到很好的优化,因为它需要汇编代码和缓存行,负载大小等知识。