Wird es effektiv sein, sich irgendwo zu beschweren, um dieses Problem zu lösen?
Leider nein. Das ist schon zu lange so und es gibt zu viel Code, der sich darauf verlässt.
Ich denke, die zugrunde liegende Frage ist "warum treten diese Inkompatibilitäten auf "? Ich werde darauf antworten. Es scheint darauf hinauszulaufen, dass BSD es zuerst implementiert, aber mit einer schlechten Schnittstelle. ISO und später GNU haben die Schnittstelle repariert und entschieden, dass sich der Kompatibilitätsbruch gelohnt hat. Und Microsoft tut, worauf sie Lust haben." P>
Wie von @Downvoter (großartiger Name) hervorgehoben, qsort_r
ist eine Nicht-Standard-Funktion. Es wäre schön, wenn es Standard wäre, aber darauf kann man sich nicht verlassen. qsort_s
ist eine Art Standard in C11 Annex K, aber niemand implementiert C11 wirklich, geschweige denn seine Anhänge, und ob Annex K eine gute Idee ist, ist fraglich.
Wie bei vielen C- und Unix-Problemen läuft dies auf BSD vs. GNU vs. Microsoft und ihre Unfähigkeit, C-Erweiterungen zu koordinieren, hinaus. Linux ist GNU. OS X ist ein Mischmasch aus vielen Dingen, aber für C folgt es BSD.
FreeBSD hat qsort_r
hinzugefügt im September 2002. Visual Studio 2005 enthielt einen etwas anderen qsort_s
. ISO formalisierte noch einmal einen anderen qsort_s
im Jahr 2007. Schließlich kamen GNUs Jahre später in glibc 2.8 im Jahr 2008, anscheinend nach ISO. Hier ist ein alter Thread aus den Jahren 2004 bis 2008, der qsort_r
anfordert in glibc implementiert werden, was einige Gründe hat.
Zur Erinnerung:Hier ist qsort
wie in C99 definiert.
void qsort(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)
);
FreeBSD war das erste im September 2002. Sie entschieden, dass qsort_r
sollte den qsort
brechen Schnittstelle und setzen Sie das "thunk"-Argument vor die Vergleichsfunktion.
void qsort_r(
void *base, size_t nmemb, size_t size,
void *thunk,
int (*compar)(void *, const void *, const void *)
);
Wieso den? Sie müssen Garrett Wollman fragen, wer den Patch geschrieben hat. Wenn man sich den Patch ansieht, sieht man seine Änderungen an CMP
Es wurde entschieden, dass es ein gutes Muster war, das "Thunk" zuerst zu haben. Vielleicht haben sie beschlossen, dass die Leute sich daran erinnern würden, dass "die Vergleichsfunktion am Ende bleibt". Leider bedeutet dies qsort
und qsort_r
Die Vergleichsfunktionen von haben ihre Argumente umgekehrt. Sehr verwirrend.
Inzwischen hat Microsoft, immer der Innovator, qsort_s
in Visual Studio 2005.
void qsort_s(
void *base, size_t num, size_t width,
int (__cdecl *compare )(void *, const void *, const void *),
void * context
);
"s" für "secure" statt "r" für "reentrant", das alle anderen möglicherweise gemäß einer ISO-Konvention (siehe unten) oder umgekehrt verwendet haben. Sie haben das "Thunk" an das Ende von qsort_s
gesetzt , wobei die Argumente dieselben wie bei qsort
bleiben , aber für maximale Verwirrung geht das "Thunk" am Anfang der Vergleichsfunktion wie BSD. Sie wählten die schlechtestmögliche Option.
Um die Sache noch schlimmer zu machen, veröffentlichte ISO 2007 TR 24731-1, um die Begrenzungsprüfung zur C-Standardbibliothek hinzuzufügen (danke @JonathanLeffler für den Hinweis). Und ja, sie haben ihren eigenen qsort_r
, aber es heißt qsort_s
! Und ja, es ist anders als alle anderen!
errno_t qsort_s(
void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context
);
Sie haben sich klugerweise entschieden, die Argumente bei qsort_s
zu belassen und seine Vergleichsfunktion eine Obermenge von qsort
wahrscheinlich argumentieren, dass es für die Leute einfacher wäre, sich zu erinnern. Und sie fügten einen Gegenwert hinzu, wahrscheinlich eine gute Idee. Um die Verwirrung noch zu verstärken, war dies damals ein "Technischer Bericht" und nicht Teil des C-Standards. Es ist jetzt "Annex K" des C11-Standards, immer noch optional, hat aber mehr Gewicht.
GNU entschied dasselbe, möglicherweise in Anlehnung an qsort_s
von ISO .
void qsort_r(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg
);
Betrachten Sie den glibc-Patch, der qsort_r
hinzufügt es war wahrscheinlich auch einfacher zu implementieren. Um es genau zu wissen, müssen Sie Ulrich Drepper fragen.
BSDs Entscheidung, Argumente mit qsort
auszutauschen und seine Vergleichsfunktion hat im Laufe der Jahre wahrscheinlich für viel Verwirrung und Fehler gesorgt. Die ISO / GNU-Entscheidung, sie gleich zu lassen, ist wohl besser. ISO entschied sich für einen anderen Namen. GNU hat beschlossen, die Kompatibilität mit der BSD-Funktion zu brechen. Microsoft beschloss, alles zu tun. Jetzt stecken wir mit vier inkompatiblen Implementierungen fest. Da die Vergleichsfunktionen unterschiedliche Signaturen haben, ist ein Kompatibilitätsmakro nicht trivial.
(Dies ist alles eine Rekonstruktion des Codes. Für ihre eigentlichen Begründungen müssen Sie die Mailinglisten-Archive durchsuchen.)
Ich kann GNU oder BSD oder ISO oder Microsoft nicht wirklich die Schuld geben ... ok, ich kann Microsoft dafür verantwortlich machen, absichtlich versucht zu haben, C zu töten schmerzhaft langsam und die Compiler-Autoren müssen manchmal tun, was sinnvoll ist.
Wie hier geschrieben, qsort
ist standardisiert (C99), aber qsort_r
ist eine GNU-Erweiterung ("qsort_r()
wurde glibc in Version 2.8 hinzugefügt"). Es gibt also keine Anforderungen dafür, dass es auf allen Plattformen gleich ist, geschweige denn portabel.