Bude pro vyřešení tohoto problému efektivní si někde stěžovat?
Bohužel ne. Je to tak už příliš dlouho a spoléhá se na to příliš mnoho kódu.
Myslím, že základní otázkou je „proč k těmto nekompatibilitám dochází "? Na to odpovím. Zdá se, že se to scvrkává na to, že jej nejprve implementovalo BSD, ale se špatným rozhraním. ISO a později GNU rozhraní opravily a rozhodly se, že narušení kompatibility za to stálo. A Microsoft dělá, co chce."
Jak zdůraznil @Downvoter (skvělé jméno), qsort_r
je nestandardní funkce. Bylo by fajn, kdyby to byl standard, ale na to se nedá spoléhat. qsort_s
je jakýmsi standardem v příloze K C11, ale nikdo ve skutečnosti neimplementuje C11, natož jeho přílohy, a zda je příloha K dobrý nápad, je otázkou.
Stejně jako mnoho problémů s C a Unixem se to týká BSD vs GNU vs Microsoft a jejich neschopnosti koordinovat rozšíření C. Linux je GNU. OS X je směs mnoha věcí, ale pro C následuje BSD.
FreeBSD přidal qsort_r
v září 2002. Visual Studio 2005 obsahovalo mírně odlišný qsort_s
. ISO formalizovalo opět jiné qsort_s
v roce 2007. Nakonec GNU přišlo o několik let později v glibc 2.8 v roce 2008 zjevně podle ISO. Zde je staré vlákno z let 2004 až 2008 požadující qsort_r
být implementován v glibc, který má určitá zdůvodnění.
Pro připomenutí všem, zde je qsort
jak je definováno v C99.
void qsort(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)
);
FreeBSD bylo první v září 2002. Rozhodli se, že qsort_r
by měl porušit qsort
rozhraní a vložte argument "thunk" před funkci porovnání.
void qsort_r(
void *base, size_t nmemb, size_t size,
void *thunk,
int (*compar)(void *, const void *, const void *)
);
Proč? Budete se muset zeptat Garretta Wollmana, kdo patch napsal. Při pohledu na patch můžete vidět z jeho změn na CMP
bylo rozhodnuto, že mít „thunk“ jako první je dobrý vzor. Možná se rozhodli, že „funkce porovnávání je na konci“ je to, co si lidé budou pamatovat. Bohužel to znamená qsort
a qsort_r
Porovnávací funkce 's mají obrácené argumenty. Velmi matoucí.
Mezitím Microsoft, vždy inovátor, má qsort_s
v aplikaci 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" pro "secure" spíše než "r" pro "reentrant", který všichni ostatní používali možná podle konvence ISO (viz níže) nebo naopak. "Thunk" umístili na konec qsort_s
, přičemž argumenty zůstanou stejné jako qsort
, ale pro maximální zmatek je "thunk" na začátku porovnávací funkce jako BSD. Zvolili nejhorší možnou variantu.
Aby toho nebylo málo, v roce 2007 ISO zveřejnilo TR 24731-1, aby přidalo kontrolu hranic do standardní knihovny C (děkuji @JonathanLeffler za upozornění). A ano, mají svůj vlastní qsort_r
, ale nazývá se qsort_s
! A ano, liší se od všech ostatních!
errno_t qsort_s(
void *base, rsize_t nmemb, rsize_t size,
int (*compar)(const void *x, const void *y, void *context),
void *context
);
Moudře se rozhodli ponechat argumenty na qsort_s
a jeho porovnávací funkce nadmnožina qsort
pravděpodobně argumentovat, že by bylo pro lidi snazší si zapamatovat. A přidali návratovou hodnotu, pravděpodobně dobrý nápad. Aby toho nebylo málo, v té době to byla „Technická zpráva“ a nebyla součástí standardu C. Nyní je to "Příloha K" standardu C11, stále volitelná, ale má větší váhu.
GNU rozhodla stejně, možná podle ISO qsort_s
.
void qsort_r(
void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg
);
Podívejte se na patch glibc, který přidává qsort_r
asi to bylo také jednodušší na realizaci. Abyste si byli jisti, budete se muset zeptat Ulricha Dreppera.
Rozhodnutí BSD zaměnit argumenty s qsort
a jeho srovnávací funkce pravděpodobně během let způsobila mnoho zmatků a chyb. Rozhodnutí ISO / GNU ponechat je stejné je pravděpodobně lepší. ISO se rozhodlo dát mu jiný název. GNU se rozhodlo prolomit kompatibilitu s funkcí BSD. Microsoft se rozhodl udělat cokoliv. Nyní jsme uvízli u čtyř nekompatibilních implementací. Protože porovnávací funkce mají různé podpisy, makro kompatibility není triviální.
(Toto vše je rekonstrukce z kódu. Pro jejich skutečné zdůvodnění se budete muset prohrabat archivy konference.)
Opravdu nemůžu vinit GNU nebo BSD nebo ISO nebo Microsoft... ok, můžu vinit Microsoft za to, že se záměrně pokusil zabít C. Pointa je proces standardizace C a rozšíření tohoto standardu a přimět kompilátory, aby tento standard dodržovaly bolestně pomalé a autoři kompilátoru musí někdy dělat to, co je vhodné.
Jak je zde napsáno, qsort
je standardizován (C99), ale qsort_r
je rozšíření GNU ("qsort_r()
byl přidán do glibc ve verzi 2.8". Neexistují tedy žádné požadavky, aby byl stejný na všech platformách, natož aby byl přenosný.