Он не является частью какого-либо стандарта ANSI, ISO или POSIX, но некоторые системы предоставляют функцию qsort_r()
, которая позволяет передавать дополнительный параметр контекста в функцию сравнения. Затем вы можете сделать что-то вроде этого:
int comp(void *thunk, const void *a, const void *b)
{
int L = (int)thunk;
// compare a and b as you would normally with a qsort comparison function
}
qsort_r(array, N, sizeof(int) * L, (void *)L, comp);
В качестве альтернативы, если у вас нет qsort_r
, вы можете использовать пакет callback(3)
из библиотеки ffcall для создания замыканий во время выполнения. Пример:
#include <callback.h>
void comp_base(void *data, va_alist alist)
{
va_start_int(alist); // return type will be int
int L = (int)data;
const void *a = va_arg_ptr(alist, const void*);
const void *b = va_arg_ptr(alist, const void*);
// Now that we know L, compare
int return_value = comp(a, b, L);
va_return_int(alist, return_value); // return return_value
}
...
// In a function somewhere
typedef int (*compare_func)(const void*, const void*);
// Create some closures with different L values
compare_func comp1 = (compare_func)alloc_callback(&comp_base, (void *)L1);
compare_func comp2 = (compare_func)alloc_callback(&comp_base, (void *)L2);
...
// Use comp1 & comp2, e.g. as parameters to qsort
...
free_callback(comp1);
free_callback(comp2);
Обратите внимание, что библиотека callback
является потокобезопасной, поскольку все параметры передаются в стеке или в регистрах. Библиотека заботится о выделении памяти, проверяя, является ли память исполняемой, и очищает кэш команд, если это необходимо, чтобы динамически сгенерированный код (то есть закрытие) выполнялся во время выполнения. Он предположительно работает на большом количестве систем, но также вполне возможно, что он не будет работать и на вашей, либо из-за ошибок, либо из-за отсутствия реализации.
Также обратите внимание, что это добавляет немного накладных расходов к вызову функции. Каждый вызов comp_base()
выше должен распаковывать свои аргументы из переданного им списка (который находится в сильно зависящем от платформы формате) и вставлять обратно возвращаемое значение. В большинстве случаев эти издержки незначительны, но для сравнения Функция, в которой фактически выполненная работа очень мала и которая будет вызываться много, много раз во время вызова на qsort()
, накладные расходы очень значительны.