有趣的strcmp实现失败。 (C)

时间:2011-10-16 22:05:59

标签: c pointers character strcmp c-strings

我正在开发一个小项目,我无法访问任何C标准库。(从头开始构建ARM结构的微内核。甚至必须实现printf)

在这种情况下,我使用Duff的机器方法实现了strcmp。

以下是整个代码。

int
strcmp ( const char *str1, const char *str2 )
{
   while ( *str1 || *str2 )
       if ( *(str1++) != *(str2++) ) return *str1 - *str2;
   return 0;
}

这是有道理的;有些时候它似乎适用于测试用例,直到最终系统发生故障。我追查到了这个strcmp。

起初我以为它首先递增str1然后与str2比较BEFORE str2递增。的 1。事实证明不是,但有人可以确认在某些情况下会发生这种情况吗?

然后我发现问题出现在* str1 - * str2中,所以将其更改为返回1.即,结果代码如下:

   while ( *str1 || *str2 )
       if ( *(str1++) != *(str2++) ) return 1;
   return 0;

虽然我想要的只是一个'等于'检查,所以改成'1'没有问题,但我仍然想知道为什么原始代码失败了。的 2。有人可以说明它是如何失败的吗?我希望strcmp遵循标准的C接口,它返回一个非零值,告诉更多关于str1和str2的信息。 / p>

测试用例是:

code_t // a function pointer type
program_find ( char *program )
{
if (strcmp( program, "exit" ) == 0) return ....
else if (strcmp( program, "k1" ) == 0) return ....
else if (strcmp( program, "k3" ) == 0) return ....
else if (strcmp( program, "perf" ) == 0) return ....
else if (strcmp( program, "test_libc" ) == 0) return ....
}

*程序为“k3”时返回“k1”,“test_libc”返回“perf”。

原来的问题是通过给它“返回1”来解决的,所以这个问题纯粹是为了C的利益。 建议或链接到strcmp文档也是受欢迎的。我见过IEEE的规范界面

4 个答案:

答案 0 :(得分:7)

在进行比较时,您在str1和str2上使用了后增量。这会导致它们在进行减法之前递增,因此您将减去错误的两个字符。

更好的实施方式是

int
strcmp ( const char *str1, const char *str2 )
{
   while ( *str1 || *str2 ) {
       if ( *str1 != *str2 ) return *str1 - *str2;
       ++str1;
       ++str2;
   }
   return 0;
}

答案 1 :(得分:4)

你有两个问题:

  • 在为返回值执行减法之前递增指针,因此返回值不正确;
  • strcmp()的特定标准表示字符串的元素被比较为unsigned char

解决这些问题:

int
strcmp ( const char *str1, const char *str2 )
{
    const unsigned char *s1 = (const unsigned char *)str1;
    const unsigned char *s2 = (const unsigned char *)str2;

    while (*s1 && *s1 == *s2) {
        s1++;
        s2++;
    }

    return *s1 - *s2;
}

答案 2 :(得分:1)

评估表达式:

*(str1++) != *(str2++)

将取消引用指针str1str2,比较结果,然后递增两个指针。到strcmp返回的时候,他们现在指的是与你比较的东西不同的东西。

请记住,实现strcmp始终返回1或0会使排序字符串列表变得无用!你需要返回-1 / 0 / + 1才能使它可用。

答案 3 :(得分:1)

int strcmp(const char* a, const char* b){
    for(;;++a,++b){
        if(*a == '\0' || *b == '\0')
            return (*a == *b)? 0 : *a != '\0' ? 1 : -1;
        if(*a != *b) return (unsigned char)(*a) > (unsigned char)(*b) ? 1 : -1;
    }
}