【问题标题】:interesting strcmp implementation failure. (C)有趣的 strcmp 实现失败。 (C)
【发布时间】:2011-10-16 22:05:59
【问题描述】:

我正在做一个小项目,我无法访问任何 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 增加之前与 str2 进行比较。 1。事实证明不是,但任何人都可以验证它在某些情况下会发生吗?

然后我发现问题出在 *str1 - *str2 中,因此将其更改为返回 1。即,生成的代码如下:

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

虽然我想要的只是一个“等于”检查,所以更改为“1”没有问题,但我仍然想知道为什么原始代码会失败。 2。有人可以就它是如何失败的给出一个提示或建议吗?我宁愿 strcmp 遵循标准 C 接口,它返回一个非零值,可以更多地了解 str1 和 str2。

测试用例是:

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 ....
}

当 *program 为“k3”时,它返回“k1”,而“test_libc”返回“perf”。

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

【问题讨论】:

标签: c pointers character strcmp c-strings


【解决方案1】:

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

更好的实现是

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

【讨论】:

    【解决方案2】:

    你有两个问题:

    • 在对返回值执行减法之前增加指针,所以返回值不正确;
    • 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;
    }
    

    【讨论】:

    【解决方案3】:

    评估表达式:

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

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

    请记住,将strcmp 实现为始终返回 1 或 0 将使其无法对字符串列表进行排序!您需要返回 -1/0/+1 以使其可用。

    【讨论】:

    • 啊,我明白了。这就是为什么 *(str1++) != *(++str2) 尝试最终没有成功的原因。
    【解决方案4】:
    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-04-24
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 2013-11-29
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多