Как я могу привести const void* к элементу структуры?

У меня есть функция сравнения для использования в qsort() следующим образом:

int compar(const void *p, const void *q){
    interval a,b;

    *p = (interval)a
    *q = (interval)b;

    if(a.extrem[1] < b.extrem[0])
        return -1;
    if(b.extrem[1] < a.extrem[0] )
        return 1;

    return 0;
}

Моя структура выглядит следующим образом:

typedef struct interval{
    double extrem[2];
    } interval;

Я пробовал много вариантов «приведения» в функции сравнения, и все они потерпели неудачу. Мой вопрос, как видно, как я могу применить const void* к моему элементу структуры? Я знаю, что это кажется очень простым вопросом, но я нигде не мог найти четкого ответа, к тому же я новичок в этом. Любая помощь приветствуется.


person l.arlev    schedule 26.05.2016    source источник
comment
a = *(interval*)p;, вероятно, это то, что вы имели в виду.   -  person Tavian Barnes    schedule 26.05.2016
comment
Вы не можете выполнять приведение к типу struct или из него. Вы можете привести void* к типу указателя или из него. (На самом деле преобразование можно выполнить неявно, без приведения.)   -  person Keith Thompson    schedule 26.05.2016
comment
С какой стати ты это делаешь? Отбрасывание всей информации о типе в ваших аргументах, а затем обработка данных как определенного типа — ужасная практика. Если кто-то вызовет это с указателем на другой тип (ничего никому не мешает!), это вызовет всевозможные проблемы. Почему бы просто не взять аргументы const ref вашего фактического типа структуры?   -  person notadam    schedule 26.05.2016
comment
@adam10603 linux.die.net/man/3/qsort   -  person Tavian Barnes    schedule 26.05.2016
comment
@TavianBarnes Да, я знаю о таких функциях, но это не то же самое. Видите ли, qsort принимает аргумент, указывающий размер вашего типа, поэтому он точно знает, насколько велик элемент. И поскольку он заботится только о байтах, которые имеет каждый элемент, а не о его типе, это совершенно нормально. В то время как рассматриваемая функция просто ожидает, что по существу бестиповый указатель будет указывать на объект точного типа, что ужасно.   -  person notadam    schedule 26.05.2016
comment
@adam10603 qsort принимает указатель на функцию int (*compar)(const void *, const void *). Он не принимает указатель на функцию int (*compar)(const interval *, const interval *).   -  person Tavian Barnes    schedule 26.05.2016
comment
@adam10603 Adam10603 Это универсальный интерфейс обратного вызова qsort(), это не его вина. :)   -  person unwind    schedule 26.05.2016
comment
@TavianBarnes сработало, спасибо.   -  person l.arlev    schedule 26.05.2016
comment
@unwind О, это обратный вызов ... Должен признаться, я полностью пропустил первую строку вопроса, мой плохой :) Я понимаю это тогда. Я думал, что это просто отдельная функция, которую написал OP, и в этом случае void* действительно было бы плохой практикой.   -  person notadam    schedule 26.05.2016
comment
Уверен, что сравнение OP не будет работать if(a.extrem[1] <b.extrem[0])return -1; if(b.extrem[1]<a.extrem[0])return 1;, учитывая его асимметрию. Непонятно, чего хочет ОП.   -  person chux - Reinstate Monica    schedule 26.05.2016
comment
@chux Кажется, это порядок интервалов, который считает перекрывающиеся интервалы равными. Это недопустимый компаратор для сортировки, потому что у вас могут быть такие интервалы, что compar(a, b) == 0 && compare(b, c) == 0, но compar(a, c) == -1.   -  person Tavian Barnes    schedule 26.05.2016


Ответы (2)


Ты был близок...

typedef struct interval {
  double extrem[2];
} interval;

int compar(const void *p, const void *q) {
  const interval *a = p, *b = q;

  if(a->extrem[1] < b->extrem[0])
    return -1;
  if(b->extrem[1] < a->extrem[0])
    return 1;
  return 0;
}

Кстати, без единого приведения это будет идеально чисто под gcc -Wall.

Обновить... Tavian делает хорошее замечание, это не транзитивный порядок, поэтому в вашем наборе технически нет частичного порядка. Но в зависимости от ваших данных и вашей цели, qsort может вернуть полезный результат даже в этом случае.

person DigitalRoss    schedule 26.05.2016

Функция qsort() будет вызывать ваш обратный вызов с указателями на элементы.

Предполагая, что массив является фактическим массивом interval, а не одним из указателей интервала, вы должны сделать:

static int interval_compare(const void *a, const void *b)
{
  const interval *ia = a, *ib = b;

  if(ia->extrem[1] < ib->extrem[0]) return -1;
  return ib->extrem[1] > ia->extrem[0];
}

Я не понимаю индексы extrem, но это то, что вы использовали. При преобразовании void * в более конкретный тип приведения не требуются. См. этот ответ.

person unwind    schedule 26.05.2016
comment
Это одномерная задача, в которой любое перекрытие считается равным, а неравенство упорядочено. Кстати, как написано прямо сейчас, это не скомпилируется. - person DigitalRoss; 26.05.2016
comment
@DigitalRoss Спасибо, исправлено. - person unwind; 26.05.2016