与qsort相比,重入qsort_r函数的可移植性如何?

qsort_r()qsort()可重入版本,它接受一个额外的’thunk’参数并将其传递给compare函数,我希望能够在便携式C代码中使用它。 qsort()是POSIX和无处不​​在,但qsort_r()似乎是一个BSD扩展。 作为一个特定问题,这是否存在或在Windows C运行时具有等效?

我试图编写一个带有示例的qsort_r / qsort_s(称为sort_r)的可移植版本。 我也把这个代码放在一个git repo中( https://github.com/noporpoise/sort_r

 struct sort_r_data { void *arg; int (*compar)(const void *a1, const void *a2, void *aarg); }; int sort_r_arg_swap(void *s, const void *aa, const void *bb) { struct sort_r_data *ss = (struct sort_r_data*)s; return (ss->compar)(aa, bb, ss->arg); } void sort_r(void *base, size_t nel, size_t width, int (*compar)(const void *a1, const void *a2, void *aarg), void *arg) { #if (defined _GNU_SOURCE || defined __GNU__ || defined __linux__) qsort_r(base, nel, width, compar, arg); #elif (defined __APPLE__ || defined __MACH__ || defined __DARWIN__ || \ defined __FREEBSD__ || defined __BSD__ || \ defined OpenBSD3_1 || defined OpenBSD3_9) struct sort_r_data tmp; tmp.arg = arg; tmp.compar = compar; qsort_r(base, nel, width, &tmp, &sort_r_arg_swap); #elif (defined _WIN32 || defined _WIN64 || defined __WINDOWS__) struct sort_r_data tmp = {arg, compar}; qsort_s(*base, nel, width, &sort_r_arg_swap, &tmp); #else #error Cannot detect operating system #endif } 

用法示例:

 #include  /* comparison function to sort an array of int, inverting a given region `arg` should be of type int[2], with the elements representing the start and end of the region to invert (inclusive) */ int sort_r_cmp(const void *aa, const void *bb, void *arg) { const int *a = aa, *b = bb, *p = arg; int cmp = *a - *b; int inv_start = p[0], inv_end = p[1]; char norm = (*a < inv_start || *a > inv_end || *b < inv_start || *b > inv_end); return norm ? cmp : -cmp; } int main() { /* sort 1..19, 30..20, 30..100 */ int arr[18] = {1, 5, 28, 4, 3, 2, 10, 20, 18, 25, 21, 29, 34, 35, 14, 100, 27, 19}; /* Region to invert: 20-30 (inclusive) */ int p[] = {20, 30}; sort_r(arr, 18, sizeof(int), sort_r_cmp, p); int i; for(i = 0; i < 18; i++) printf(" %i", arr[i]); printf("\n"); } 

编译/运行/输出:

 $ gcc -Wall -Wextra -pedantic -o sort_r sort_r.c $ ./sort_r 1 2 3 4 5 10 14 18 19 29 28 27 25 21 20 34 35 100 

我在mac和linux上测试过。 如果您发现错误/改进,请更新此代码。 您可以根据需要自由使用此代码。

对于Windows,您将使用qsort_s : http : //msdn.microsoft.com/en-us/library/4xc60xas( qsort_s .aspx

显然有一些关于BSD和GNU有qsort_r版本不兼容的qsort_r ,所以在生产代码中使用它要小心: http : //sourceware.org/ml/libc-alpha/2008-12/msg00003.html

顺便说一句, _s代表“安全”而_r代表“重入”,但两者都意味着有一个额外的参数。

它没有在任何可移植性标准中指定。 另外我认为将它称为qsort的“线程安全”版本是错误的。 标准qsort是线程安全的,但qsort_r有效地允许您传递一个闭包作为比较函数。

显然,在单线程环境中,您可以使用全局变量和qsort实现相同的结果,但这种用法不是线程安全的。 线程安全的另一种方法是使用特定于线程的数据,并让比较函数从特定于线程的数据中检索其参数( pthread_getspecific与POSIX线程,或gcc中的__thread变量和即将推出的C1x标准)。