2015-05-01 4 views
2

Рассмотрим массив из указателей на структуры. Следующий код берется из примера, вы можете найти here. Я бы хотел получить объяснение для этих двух рядов кастинга. Я не знаком с этим «двойным кастингом».qsort() и операция литья

int myptrstructcmp(const void *p1, const void *p2) 
{ 
    struct mystruct *sp1 = *(struct mystruct * const *)p1; 
    struct mystruct *sp2 = *(struct mystruct * const *)p2; 

Я подумал, что это должно быть:

int myptrstructcmp(const void *p1, const void *p2) 
{ 
    struct mystruct *sp1 = (struct mystruct *)p1; 
    struct mystruct *sp2 = (struct mystruct *)p2; 
+0

Когда 'qsort()' вызывает вашу функцию сравнения, он не может передать * значение * двух элементов массива, которые он хочет сравнить, потому что они не имеют постоянного размера. Таким образом, он вместо этого передает * указатели * в начало элементов массива, которые он хочет сравнить. – EOF

+0

В C (во втором) этот актер не нужен! Правильно - второе! Если вы используете первое, вы говорите, что хотите назначить содержимое структуры структуре! * Вне скобки означает, что вы хотите, чтобы содержимое указывалось p, литой означает, что содержимое имеет тип struct mystruct !. В примере, который вы цитируете, не выбраны, а *. –

+0

В чем смысл 'struct mystruct * const *'? Без 'const *' он не может корректно отображать. Зачем? – abcxyz

ответ

5

Предположим, вы разбирали массив int. Вашему компаратору будет передана пара int *, замаскированная под void *; добавляется один уровень косвенности.

Если вы сортируете массив из struct mystruct *, ваш компаратор передается struct mystruct ** замаскирован под void *; добавляется один уровень косвенности.

В чем смысл struct mystruct * const *? Без const* он не может правильно отобразить. Зачем?

Что означает «без const *», он не правильно выбрасывает? » Без const он работает нормально. Без второго * он не работает, потому что функция передается struct mystruct ** (дайте или возьмите некоторую константу), и если вы опустите вторую звезду, вы злоупотребляете системой типов.

Рассмотрим:

struct mystruct 
{ 
    int i; 
}; 

int myptrstructcmp(const void *p1, const void *p2); 
int myptrstructcmp(const void *p1, const void *p2) 
{ 
    struct mystruct *sp1 = *(struct mystruct **)p1; 
    struct mystruct *sp2 = *(struct mystruct **)p2; 

    if (sp1->i < sp2->i) 
     return -1; 
    else if (sp1->i > sp2->i) 
     return +1; 
    else 
     return 0; 
} 

Это нормально компилируется. Он также отлично компилируется при добавлении const между **. Лично я бы не включил const в литье. Что бы я сделал это сопзЬ-квалифицируют sp1 и sp2 указатели:

struct mystruct const *sp1 = *(struct mystruct **)p1; 
    struct mystruct const *sp2 = *(struct mystruct **)p2; 

или:

const struct mystruct *sp1 = *(struct mystruct **)p1; 
    const struct mystruct *sp2 = *(struct mystruct **)p2; 

Это обещает не изменять объекты, которые они указывают на в функции, которая на самом деле важно правильная производительность qsort().

3

Вот ваш ключ — в C FAQ вы ссылаетесь:

Если, с другой стороны, вы сортировка указателей на структуры, вы будете нуждаться в окольном,

Вы разбираете список указателей на структуры. Указатели должны быть перепутаны в списке по типу, что означает, что вы передаете указатели в списке по ссылке (через указатель на указатель) для сравнения.

+0

Есть ли источник, который вы цитируете? Если это так, вы должны включить ссылку на источник (или определить его как-то). –

+0

Согласовано. Источник был предоставлен OP в предложении: > Следующий код берется из примера, который вы можете найти здесь. – koan911

2

man qsort От:

[...] функция сравнения [..], который вызывается с двумя аргументами, которые указывают на сравниваемых объектов.

«сравниваемых объектов» являются элементами массива, переданного qsort() и в этом массиве будут отсортированы трюмы указатели функция сравнительную получает указатель на указатель в качестве аргументов.

Чтобы получить элементы массива из аргументов, переданных функции сопоставления, эти аргументы необходимо отменить.

1

Функция сравнения принимает указатели элементы массива. Если ваш массив содержит элементы некоторого типа T, тогда ваша сравнительная функция примет const void * указатели, которые следует трактовать как const T * указатели.

В вашем случае T равен struct mystruct * (так как ваш массив содержит указатели). В этом случае const T * эквивалентен struct mystruct * const*, что и есть то, что вы видите в своем коде.

Для того, чтобы сделать код легче понять, вы можете буквально ввести имя ЬурейеГо T в функцию и разделить ваши преобразования/разыменовывает в отдельный человек шаги

int myptrstructcmp(const void *p1, const void *p2) 
{ 
    typedef mystruct *T;    // array elements are pointers 
    const T *pel1 = p1, *pel2 = p2; // pointers to array elements 
    T sp1 = *pe1, sp2 = *pe2;  // values of array elemnts 

Это равносильно тому, что вы имеете в исходный код;

Смежные вопросы