Sera-t-il efficace de se plaindre quelque part pour résoudre ce problème ?
Hélas non. C'est comme ça depuis trop longtemps et il y a trop de code qui en dépend.
Je pense que la question sous-jacente est "pourquoi ces incompatibilités se produisent "? Je vais répondre à cela. Cela semble se résumer à ce que BSD l'implémente en premier mais avec une interface médiocre. ISO et plus tard GNU ont corrigé l'interface et ont décidé que la rupture de compatibilité en valait la peine. Et Microsoft fait ce qu'il veut.
Comme l'a souligné @Downvoter (grand nom), qsort_r
est une fonction non standard. Ce serait bien si c'était standard, mais vous ne pouvez pas compter là-dessus. qsort_s
est une sorte de norme dans l'annexe K de C11, mais personne ne met vraiment en œuvre C11, encore moins ses annexes, et la question de savoir si l'annexe K est une bonne idée est en cause.
Comme beaucoup de problèmes C et Unix, cela se résume à BSD contre GNU contre Microsoft et leur incapacité à coordonner les extensions C. Linux est GNU. OS X est un méli-mélo de beaucoup de choses, mais pour C, il suit BSD.
FreeBSD a ajouté qsort_r
en septembre 2002. Visual Studio 2005 comportait un qsort_s
légèrement différent . L'ISO a formalisé un encore différent qsort_s
en 2007. Enfin, GNU est arrivé des années plus tard dans la glibc 2.8 en 2008, apparemment après ISO. Voici un vieux fil couvrant 2004 à 2008 demandant qsort_r
être implémenté dans la glibc qui a quelques justifications.
Pour rappel à tous, voici qsort
tel que défini dans C99.
void qsort(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)
);
FreeBSD a été le premier en septembre 2002. Ils ont décidé que qsort_r
devrait casser le qsort
interface et placez l'argument "thunk" avant la fonction de comparaison.
void qsort_r(
void *base, size_t nmemb, size_t size,
void *thunk,
int (*compar)(void *, const void *, const void *)
);
Pourquoi? Vous devrez demander à Garrett Wollman qui a écrit le patch. En regardant le patch, vous pouvez voir ses modifications apportées à CMP
il a été décidé qu'avoir le "thunk" en premier était un bon modèle. Peut-être qu'ils ont décidé que "la fonction de comparaison va à la fin" était ce dont les gens se souviendraient. Malheureusement, cela signifie qsort
et qsort_r
Les fonctions de comparaison de ont leurs arguments inversés. Très déroutant.
Pendant ce temps, Microsoft, toujours l'innovateur, a qsort_s
dans 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" pour "sécurisé" plutôt que "r" pour "réentrant" que tout le monde utilisait éventuellement en suivant une convention ISO (voir ci-dessous) ou vice-versa. Ils ont mis le "thunk" à la fin de qsort_s
, en gardant les mêmes arguments que qsort
, mais pour un maximum de confusion, le "thunk" va au début de la fonction de comparaison comme BSD. Ils ont choisi la pire option possible.
Pour aggraver les choses, en 2007, l'ISO a publié TR 24731-1 pour ajouter la vérification des limites à la bibliothèque standard C (merci @JonathanLeffler pour l'avoir signalé). Et oui, ils ont leur propre qsort_r
, mais il s'appelle qsort_s
! Et oui, c'est différent de tout le monde !
errno_t qsort_s(
void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context
);
Ils ont sagement décidé de garder les arguments à qsort_s
et sa fonction de comparaison un sur-ensemble de qsort
arguant probablement qu'il serait plus facile pour les gens de s'en souvenir. Et ils ont ajouté une valeur de retour, probablement une bonne idée. Pour ajouter à la confusion, à l'époque, il s'agissait d'un "rapport technique" et ne faisait pas partie de la norme C. C'est maintenant "l'annexe K" de la norme C11, toujours facultative mais qui a plus de poids.
GNU a décidé la même chose, peut-être en suivant le qsort_s
de l'ISO .
void qsort_r(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg
);
En regardant le patch glibc en ajoutant qsort_r
c'était probablement aussi plus facile à mettre en œuvre. Pour en être sûr, il faudra demander à Ulrich Drepper.
Décision de BSD d'échanger les arguments avec qsort
et sa fonction de comparaison a probablement causé beaucoup de confusion et de bugs au fil des ans. La décision ISO / GNU de les garder identiques est sans doute meilleure. L'ISO a décidé de lui donner un nom différent. GNU a décidé de rompre la compatibilité avec la fonction BSD. Microsoft a décidé de faire n'importe quoi. Nous sommes maintenant coincés avec quatre implémentations incompatibles. Étant donné que les fonctions de comparaison ont des signatures différentes, une macro de compatibilité n'est pas triviale.
(Tout cela est une reconstruction à partir du code. Pour leurs justifications réelles, vous devrez fouiller dans les archives de la liste de diffusion.)
Je ne peux pas vraiment blâmer GNU ou BSD ou ISO ou Microsoft ... ok, je peux blâmer Microsoft pour avoir délibérément essayé de tuer C. Le point est le processus de standardisation de C, et d'extension de cette norme, et d'amener les compilateurs à suivre cette norme est extrêmement lent et les auteurs du compilateur doivent parfois faire ce qui est opportun.
Comme écrit ici, qsort
est normalisé (C99), mais qsort_r
est une extension GNU ("qsort_r()
a été ajouté à la glibc dans la version 2.8"). Ainsi, il n'y a aucune exigence pour qu'elle soit la même sur toutes les plates-formes, et encore moins portable.