この問題を解決するためにどこかに文句を言うことは有効でしょうか?
ああ、いいえ。あまりにも長い間この方法であり、それに依存するコードが多すぎます。
根本的な問題は、「なぜこれらの非互換性が発生するのか」だと思います "? 私はそれに答えます. 要するに BSD が最初にそれを実装するように見えますが、インターフェースは貧弱です. ISO とその後の GNU はインターフェースを修正し、互換性を損なう価値があると判断しました. そして Microsoft は彼らが好きなように何でもします.
@Downvoter (偉大な名前) が指摘したように、 qsort_r
非標準関数です。標準だったらいいのですが、あてにできません。 qsort_s
は C11 附属書 K の一種の標準ですが、その附属書は言うまでもなく、C11 を実際に実装している人は誰もいません。また、附属書 K が良いアイデアであるかどうかは疑問です.
多くの C および Unix の問題と同様に、これは BSD vs GNU vs Microsoft と、C 拡張機能を調整できないことに帰着します。 Linux は GNU です。 OS X は多くのものの寄せ集めですが、C では BSD に従います。
FreeBSD は qsort_r
を追加しました 2002 年 9 月。Visual Studio 2005 では、わずかに異なる qsort_s
. ISO が再び正式化 qsort_s
2007年に。ついにGNUは、明らかにISOに続いて、2008年にglibc 2.8で数年後に登場しました。これは、2004 年から 2008 年にかけて qsort_r
を要求する古いスレッドです。 いくつかの理論的根拠を持つ glibc で実装されます。
qsort
です。 C99 で定義されています。
void qsort(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)
);
FreeBSD は 2002 年 9 月に最初のものでした。彼らは qsort_r
qsort
を壊す必要があります インターフェイスを開き、比較関数の前に「サンク」引数を置きます。
void qsort_r(
void *base, size_t nmemb, size_t size,
void *thunk,
int (*compar)(void *, const void *, const void *)
);
なんで?パッチを書いた Garrett Wollman に尋ねる必要があります。パッチを見ると、彼の CMP
への変更からわかります 「サンク」を最初に持つのが良いパターンであると判断されました。おそらく彼らは、「比較関数は最後に行く」ということを人々が覚えていると判断したのかもしれません。残念ながら、これは qsort
を意味します と qsort_r
の比較関数は引数が逆になっています。非常に紛らわしいです。
一方、革新者である Microsoft には qsort_s
があります。 Visual Studio 2005 で。
void qsort_s(
void *base, size_t num, size_t width,
int (__cdecl *compare )(void *, const void *, const void *),
void * context
);
「再入可能」を表す「r」ではなく、「安全」を表す「s」は、他のすべての人が ISO 規則 (以下を参照) に従って使用していた可能性があり、その逆も同様です。 qsort_s
の最後に「サンク」を付けます 、引数を qsort
と同じに保ちます 、しかし最大の混乱のために、「サンク」は BSD のような比較関数の先頭に置かれます。彼らは最悪の選択肢を選びました.
さらに悪いことに、2007 年に ISO は TR 24731-1 を公開して、C 標準ライブラリに境界チェックを追加しました (指摘してくれた @JonathanLeffler に感謝します)。はい、彼らは独自の qsort_r
を持っています 、しかしそれは qsort_s
と呼ばれます !そうです、他の人とは違います!
errno_t qsort_s(
void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context
);
彼らは賢明にも引数を qsort_s
にしておくことにしました およびその比較関数は qsort
のスーパーセット おそらく、人々が覚えやすいと主張しています。そして、彼らは戻り値を追加しました。おそらく良い考えです。さらに混乱を招くのは、当時、これは「テクニカル レポート」であり、C 標準の一部ではありませんでした。これは現在、C11 標準の「Annex K」であり、オプションですが、より重要です。
GNU は、おそらく ISO の qsort_s
に従って、同じことを決定しました。 .
void qsort_r(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg
);
qsort_r
を追加する glibc パッチを見る おそらく実装も簡単でした。確実に知るには、Ulrich Drepper に聞く必要があります。
qsort
で引数を交換するという BSD の決定 その比較機能はおそらく、長年にわたって多くの混乱とバグを引き起こしてきました。それらを同じに保つというISO / GNUの決定は、間違いなく優れています。 ISO は別の名前を付けることにしました。 GNU は BSD 関数との互換性を壊すことを決定しました。マイクロソフトは何でもすることにしました。現在、互換性のない実装が 4 つ残っています。比較関数には異なる署名があるため、互換性マクロは自明ではありません。
(これはすべてコードからの再構成です。実際の理論的根拠については、メーリング リストのアーカイブを掘り下げる必要があります。)
GNU や BSD や ISO や Microsoft を本当に責めることはできません... OK、C を故意に殺そうとしたことで Microsoft を責めることはできます。痛ましいほど遅く、コンパイラの作成者は時折、都合のよいことをしなければなりません。
ここに書かれているように、 qsort
標準化 (C99) されていますが、qsort_r
GNU 拡張 ("qsort_r()
バージョン 2.8 で glibc に追加されました")。したがって、プラットフォーム間で同じである必要はなく、移植性は言うまでもありません。