这个函数可以在这里找到。它是strcmp
的一种实现方式:
int strcmp(const char* s1, const char* s2)
{
while (*s1 && (*s1 == *s2))
s1++, s2++;
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
我理解前面的所有内容,但最后一行是什么意思?
这个函数可以在这里找到。它是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: 简而言之,最后一行发生了什么?
A: 首先比较潜在的字符串差异。两个chars
按规范要求都被引用为unsigned char
。它们被提升为int
并返回差异。
注:
1 返回值的符号(<0、0、>0)是最有意义的部分。这是C规范指定的唯一部分。
2 在某些系统上,char
是signed
(更常见)。在其他系统上,char
是unsigned
。定义最后一个比较的“符号性”有助于提高可移植性。请注意,fgetc()
以unsigned char
获取字符。
3 除了字符串以\0
结尾外,所采用的字符编码(如ASCII-最常见)在二进制级别上没有任何区别。如果两个字符串中第一个不同的char
的值为65和97,则第一个字符串将小于第二个字符串,即使字符编码是非ASCII的。然而,当字符编码为ASCII时,strcmp("A", "a")
将返回负数,但在不同的字符编码中,它们的基础值和顺序未被C定义,可能会返回正数。
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机器代码更差(我不知道为什么)。
s1 = (unsigned char)*str1++;
,以实现strcmp()
的确切语义。 - chqrlie这个实现绝对不是内置的strcmp
函数的优化版本,它只是另一种实现方式,我相信它很可能比内置版本表现更差。
比较函数应该返回0,如果被比较的值相等,如果第一个值较小,则返回任何负数,如果第一个值较大,则返回任何正数。这就是最后一行发生的事情。
最后一行的想法是将字符转换为无符号字符,并且我相信作者的意图是将非标准字符(ASCII码0-127之外的字符)排在标准字符之后。
编辑:代码中没有错误,如果指向s1
的值小于指向s2
的值,则可以并且将返回负值,将标准字符排在具有128及以上代码的字符之前。
这个实现可以进一步优化,减少一些比较:
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标准确定。
If char
is smaller than int
, which is true on all but some rare embedded systems, this difference can be computed with a simple subtraction, both c1
and c2
being promoted to int
and this difference is guaranteed to fit in the range of type int
.
On systems where sizeof(int) == 1
, the return value should be computed this way:
return (c1 < c2) ? -1 : 1;
strcmp
返回的是哪个字符串比另一个字符串“大”,而不仅仅是它们是否相等。
最后一行减去第一个不匹配的字符,以查看哪个更大。如果整个字符串匹配,则为 0-0=0
,这将给出“相等”的结果。
这种实现并没有真正优化,因为那需要汇编代码和对缓存行、加载大小等的了解。