2

マニュアルページから:

strcmp()およびstrncmp()関数は、s1(またはその最初のnバイト)がそれぞれs2より小さい、一致する、または大きいことがわかった場合、ゼロより小さい、等しい、またはより大きい整数を返します。 。

Cのサンプルコード(-15私のマシンで印刷し、test1とtest2を交換すると値が反転します):

#include <stdio.h>
#include <string.h>

int main() {
    char* test1 = "hello";
    char* test2 = "world";
    printf("%d\n", strcmp(test1, test2));
}

strcmpの値が-1、0、1以外のものであることに依存するこのコードこの質問から取得)を見つけました(の戻り値を使用しますqsort)。私にとって、これはひどいスタイルであり、文書化されていない機能に依存します。

私は2つの関連する質問があると思います:

  • C標準には、ゼロ未満、ゼロより大きい、またはゼロに等しい以外の戻り値を定義するものがありますか?そうでない場合、標準の実装は何をしますか?
  • 戻り値はLinux、Windows、およびBSD間で一貫していますか?

編集:

コンピューターを5分間放置した後、問題のコードに実際にはエラーがないことに気付きました。コメント/回答を読む前に理解した部分を削除しましたが、コメントを適切に保つためにそこに残しました。これはまだ興味深い質問であり、常に-1、0、または1を返す他の言語に慣れているプログラマーに問題を引き起こす可能性があると思います(たとえば、Pythonはこれを行うようですが、そのように文書化されていません)。

FWIW、文書化された動作以外のものに依存するのは悪いスタイルだと思います。

4

7 に答える 7

7

C標準には、ゼロ未満、ゼロより大きい、またはゼロに等しい以外の戻り値を定義するものがありますか?

いいえ。最も厳しい制約は、この特定の関数のドキュメントで指定されているように、ゼロ、ゼロ未満、またはゼロより大きい必要があるということです。

そうでない場合、標準の実装は何をしますか?

「標準実装」のようなものはありません。あったとしても、たぶん

return zero, less than zero or more than zero;

:-)

戻り値はLinux、Windows、およびBSD間で一貫していますか?

10.7.4の時点でLinuxとOSXで一貫していることを確認できます(具体的には、-1、0、または+1です)。私はWindowsについてはわかりませんが、Microsoftの人たちはコードを壊すためだけに-2と+3を使用しているに違いありません:P

また、コードの機能を完全に誤解していることも指摘しておきます。

strcmpの値が-1、0、1以外のものであることに依存するこのコード(この質問から取得)を見つけました(qsortの戻り値を使用します)。私にとって、これはひどいスタイルであり、文書化されていない機能に依存します。

いいえ、実際にはそうではありません。C標準ライブラリは、一貫性と使いやすさを念頭に置いて設計されています。つまり、qsort()必要なのは、そのコンパレータ関数が負または正の数またはゼロを返すことです。これはまさにstrcmp()保証されていることです。したがって、これは「ひどいスタイル」ではなく、文書化されていない機能に依存しない、完全に標準に準拠したコードです。

于 2012-11-26T19:44:48.570 に答える
4

C99標準では、§7.21.4.2strcmp関数

この関数は、が指す文字列が。が指す文字列よりも大きい、等しい、または小さいため、ゼロより大きい、等しい、またはより小さいstrcmp整数を返します。s1s2

強調が追加されました。

-1これは、標準が、、0または1;について保証しないことを意味します。オペレーティングシステムによって異なる場合があります。

w取得する値は、との差hです15

あなたの場合helloなど、worldそれが-15を返す'h'-'w' = -15 < 0理由です。strcmp

于 2012-11-26T19:45:44.997 に答える
4

•C標準には、ゼロ未満、ゼロより大きい、またはゼロに等しい以外の戻り値を定義するものがありますか。そうでない場合、標準の実装は何をしますか?

いいえ、あなたがあなた自身に言ったように、manページは言います、less than, equal to, or greater than zeroそしてそれは標準が同様に言うことです。

•戻り値は、Linux、Windows、およびBSD間で一貫していますか。

いいえ。

Linux(OpenSuSE 12.1、カーネル3.1)でgccを使用すると、/が最初かどうかに応じて-15/を取得します。Windows 7(VS 2010)では/を取得します。15test1test2-11

の大まかな定義に基づいてstrcmp()、どちらも問題ありません。


...これは、strcmpの値が-1、0、および1以外のものであることに依存しています(qsortの戻り値を使用します)。

興味深い補足事項... qsort()manページを見ると、そこにある例は、を使用して投稿したBellコードとほとんど同じですstrcmp()。必要なコンパレータ関数である理由は、qsort()実際には:からの戻りに最適です。strcmp()

比較関数は、最初の引数がそれぞれ2番目の引数よりも小さい、等しい、または大きいと見なされる場合、ゼロより小さい、等しい、またはより大きい整数を返す必要があります。

于 2012-11-26T19:53:07.913 に答える
1

実際には、の戻り値はstrcmp、最初の位置で異なるバイトの値の差である可能性があります。これは、この差を返す方が、追加の条件分岐を実行して-1または1に変換するよりもはるかに効率的だからです。残念ながら、一部の壊れたソフトウェアは、結果が8ビットに収まると想定し、深刻な脆弱性をもたらすことが知られています。つまり、結果の符号以外は使用しないでください。

問題の詳細については、上記でリンクした記事をお読みください。

https://communities.coverity.com/blogs/security/2012/07/19/more-defects-like-the-mysql-memcmp-vulnerability

于 2012-11-26T19:56:02.170 に答える
1

このページの内容

strcmp()関数は、s1が指す文字列をs2が指す文字列と比較します。ゼロ以外の戻り値の符号は、比較される文字列が異なる最初のバイトのペア(両方ともunsigned char型として解釈される)の値の差の符号によって決定されます。

これがFreeBSDでのstrcmp実装です。

#include <string.h>

/*
 * Compare strings.
 */
int
strcmp(s1, s2)
    register const char *s1, *s2;
{
    while (*s1 == *s2++)
        if (*s1++ == 0)
            return (0);
    return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}
于 2012-11-26T20:06:42.837 に答える
0

C標準には、によって返される値について説明するものはありません(つまり、その値の符号strcmp()以外はありません)。

7.21.4.2strcmp関数

あらすじ

#include <string.h>
int strcmp(const char *s1, const char *s2);

説明

strcmp関数は、s1が指す文字列をs2が指す文字列と比較します。

戻り値

strcmp関数は、s1が指す文字列が、s2が指す文字列より大きい、等しい、または小さいため、ゼロより大きい、等しい、またはより小さい整数を返します。

したがって、戻り値の符号以外のものを使用することは不適切な方法であることは明らかです。

于 2012-11-26T19:46:11.720 に答える
0

マニュアルページから:

戻り値strcmp()およびstrncmp()関数は、s1(またはその最初のnバイト)がそれぞれより小さい、一致する、または大きいことがわかった場合、ゼロより小さい、等しい、またはより大きい整数を返します。 s2より。

それはそれが0より大きいか小さいことを指定するだけであり、特定の値については何も言わず、それらは私が推測する実装固有のものです。

SVr4、4.3BSD、C89、C99に準拠しています。これは、それがどの規格に含まれているかを示しています。関数は存在し、指定どおりに動作する必要がありますが、仕様には実際の戻り値については何も記載されていないため、それらに依存することはできません。

于 2012-11-26T19:46:00.630 に答える