PHPのstrcmp関数の挙動について教えて下さい。


オライリーの「プログラミングPHP(第三版)」には以下のような旨の記述があります。
「$n=strcmp("PHP最高!",5)の出力結果は1となる。」

こちらの環境では出力結果は59となりました。


また、適当な入門サイトを見ると下記のようなことが書いてありました。
$str1 = 'PHP入門';
$str2 = 'php関数入門';
$str3 = 'PHPタグ入門';
$str4 = 'PHP入門';

echo strcmp($str1, $str2);
出力→-1
echo strcmp($str1, $str3);
出力→1
echo strcmp($str1, $str4);
出力→0

こちらの出力結果は上から-32,2,0となりました。

環境はmacのxampp1.7.3beta1(PHP5.3.1)です。
バージョンによってこんなに関数の挙動が変わってくるとも思えないので、何か他の原因があるのでしょうか?また、その他で何か間違ってそうなところはありますか?

以上お願い致します。

回答の条件
  • 1人3回まで
  • 登録:
  • 終了:2015/10/31 09:20:52
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。
id:kojikoji75

Windowsのxamppでは正常な結果が得られました。

質問の内容が分散していました。

ここでききたかったことは、"PHP最高"と5を比較して、どうして1を返すかということでした。その辺りについて解説をなかなか見つけることができないのでここで質問させていただきました。

あらためてよろしくお願い致します。

ベストアンサー

id:soqans No.1

回答回数9ベストアンサー獲得回数3

ポイント100pt

戻り値が異なる理由は突き詰めると「PHPを実行するプログラムを作り出したプログラム」に依存する、というものです。

説明をしますと、PHPのstrcmp関数は内部的に
・比較対象の値を強制的に文字列に変換する(型キャストにより文字列型に変換したときと同じ動作)
・文字列化したそれぞれの値をC言語のmemcmp関数で比較(短い方の長さまで)
・異なる場合はmemcmp関数の結果、同じ場合は長さの差を返す
という動作をおこなっているようです。ところが、このmemcmp関数は「比較対象の文字列が前にあるときは負の値、等しいときは0、後ろにあるときは正の値を返す、という仕様を満たす動作を行う」としか決められていません。そのため、仕様が満たされていれば返す値は何でも良い、ということになっています。

このmemcmp関数ですが、いくつかのコンパイラで動作を見てみると、
・VisualStudio系(Windows):-1or0or1の3値のみ返す
・Xcode系(Mac):バイナリの差分値を返す
・GCC系(主にLinux):-1or0or1の3値のみ返す
という結果となりました。
おそらくこれが書籍とMacの環境で結果が異なる理由だと思います。

初めの質問文ですが5を文字列に変換して文字コード(UTF-8)を取ると
"P":0x50
"p":0x70
"5":0x35
ですので、"php最高"と5をstrcmpで比較すると"p"-"5"=59となって、正の数なので1が返される、という処理と考えられます。
(小文字でも大文字でも正の数ですのでWinもしくはLinuxでは1ですが、Mac環境では小文字では59、大文字では27になると思います)

もう一つの質問にある-1および1を返す例ですが、UTF-8を使用している場合(0xというのは16進数表記を表しますが)
"入":0xE5 0x85 0xA5
"タ":0xE3 0x82 0xBF
となるので、(初めに異なっている位置だけ見ると)"P"-"p"=-32、"入"-"タ"=2となり、Macの結果は記述の通りとなり、値を-1~1へ変換するものでは-1と1を返す、という動作だと思われます。

id:kojikoji75

ありがとうございました。
知りたい部分を知ることができました。

2015/10/31 09:20:36

その他の回答0件)

id:soqans No.1

回答回数9ベストアンサー獲得回数3ここでベストアンサー

ポイント100pt

戻り値が異なる理由は突き詰めると「PHPを実行するプログラムを作り出したプログラム」に依存する、というものです。

説明をしますと、PHPのstrcmp関数は内部的に
・比較対象の値を強制的に文字列に変換する(型キャストにより文字列型に変換したときと同じ動作)
・文字列化したそれぞれの値をC言語のmemcmp関数で比較(短い方の長さまで)
・異なる場合はmemcmp関数の結果、同じ場合は長さの差を返す
という動作をおこなっているようです。ところが、このmemcmp関数は「比較対象の文字列が前にあるときは負の値、等しいときは0、後ろにあるときは正の値を返す、という仕様を満たす動作を行う」としか決められていません。そのため、仕様が満たされていれば返す値は何でも良い、ということになっています。

このmemcmp関数ですが、いくつかのコンパイラで動作を見てみると、
・VisualStudio系(Windows):-1or0or1の3値のみ返す
・Xcode系(Mac):バイナリの差分値を返す
・GCC系(主にLinux):-1or0or1の3値のみ返す
という結果となりました。
おそらくこれが書籍とMacの環境で結果が異なる理由だと思います。

初めの質問文ですが5を文字列に変換して文字コード(UTF-8)を取ると
"P":0x50
"p":0x70
"5":0x35
ですので、"php最高"と5をstrcmpで比較すると"p"-"5"=59となって、正の数なので1が返される、という処理と考えられます。
(小文字でも大文字でも正の数ですのでWinもしくはLinuxでは1ですが、Mac環境では小文字では59、大文字では27になると思います)

もう一つの質問にある-1および1を返す例ですが、UTF-8を使用している場合(0xというのは16進数表記を表しますが)
"入":0xE5 0x85 0xA5
"タ":0xE3 0x82 0xBF
となるので、(初めに異なっている位置だけ見ると)"P"-"p"=-32、"入"-"タ"=2となり、Macの結果は記述の通りとなり、値を-1~1へ変換するものでは-1と1を返す、という動作だと思われます。

id:kojikoji75

ありがとうございました。
知りたい部分を知ることができました。

2015/10/31 09:20:36
  • id:tezcello
    この関数は、0(与えた文字列が同じ)であるかどうかを判断するもので、0以外の戻り値には「与えた文字列が同じではない」以上の意味が無いのではありませんか?

    何となくですが、文字のエンコードの違いで戻り値が異なるんじゃないかと予想はしますが。
  • id:kojikoji75
    ご回答ありがとうございます。

    strcmp(string1,string2)は、string1<string2の場合に負の値、string1>string2の場合に正の値を返すとのことなので、知りたいのは"PHP最高!"と5(数値型)の比較でどのように大小比較をしているのかというところです。

    比較演算子(<,<=,>,>=)で、文字列と数値を比較した場合は、「文字列は数値に変換されて0になる」とまで書かれてあるのに、strcmpに関しては「必要に応じて数字を文字列にキャストします」とだけ書いてあって、どう変換するか、どう比較するかまで書いてなかったので気になりました。

    最初に質問したmac環境の方は一旦忘れることにします。すみません。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません