0

私は、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 は、str1 と str2 について詳しく説明するゼロ以外の値を返すという標準の C インターフェイスに従う必要があります。

テストケースは次のとおりです。

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 の仕様インターフェイスを見てきました

4

4 に答える 4

7

比較を行うときは、str1とstr2でポストインクリメントを使用しています。これにより、減算を実行する前にインクリメントされるため、間違った2文字を減算しています。

より良い実装は

int
strcmp ( const char *str1, const char *str2 )
{
   while ( *str1 || *str2 ) {
       if ( *str1 != *str2 ) return *str1 - *str2;
       ++str1;
       ++str2;
   }
   return 0;
}
于 2011-10-16T22:09:53.980 に答える
4

2 つの問題があります。

  • 戻り値の減算を実行する前にポインターをインクリメントするため、戻り値は正しくありません。
  • for 固有の標準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;
}
于 2011-10-16T23:04:01.860 に答える
1

式の評価:

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

ポインタstr1を逆参照しstr2、結果を比較してから、両方のポインタをインクリメントします。戻ってきた時点でstrcmp、彼らはあなたが比較したものとは異なる何かを指し示しています。

常に1または0を返すように実装strcmpすると、文字列のリストを並べ替えるのに役に立たなくなることに注意してください。そのために使用できるようにするには、-1 / 0 /+1を返す必要があります。

于 2011-10-16T22:13:12.220 に答える
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;
    }
}
于 2011-10-17T00:35:33.013 に答える