首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与qsort相比,可重入qsort_r函数的可移植性如何?

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

Stack Overflow用户
提问于 2010-11-29 12:37:00
回答 3查看 8.6K关注 0票数 10

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-02-11 02:59:29

我尝试编写一个示例所示的qsort_r / qsort_s (称为sort_r)的可移植版本。我还将这段代码放入了一个git代码库(https://github.com/noporpoise/sort_r)

代码语言:javascript
复制
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
}

示例用法:

代码语言:javascript
复制
#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");
}

编译/运行/输出:

代码语言:javascript
复制
$ 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上测试过了。如果发现错误/改进,请更新此代码。您可以根据自己的意愿自由使用此代码。

票数 11
EN

Stack Overflow用户

发布于 2010-11-29 12:40:33

对于Windows,您将使用qsort_shttp://msdn.microsoft.com/en-us/library/4xc60xas(VS.80).aspx

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

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

票数 9
EN

Stack Overflow用户

发布于 2010-11-29 12:44:59

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

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4300896

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档