![](/img/trans.png)
[英]What is a 'thunk'? (in the context of re-entrant sort functions, eg: qsort_r)
[英]How portable is the re-entrant qsort_r function compared to qsort?
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 <stdio.h>
/* 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標准)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.