Каковы различные стили определения функции, возвращающей указатель на функцию

#c #pointers

#c #указатели

Вопрос:

У меня есть одна функция:

 int compare(char * c1, char * c2){
...
...
}
 

Каковы различные стили, в которых я могу написать функцию int ret_compare(void * item) , которая возвращает указатель для сравнения?

Ответ №1:

Существует два основных стиля: один использует a typedef , а другой нет (с двумя вариантами typedef ). Ваш компаратор должен принимать постоянные указатели, как показано ниже:

 int compare(const char *c1, const char *c2) { ... }

// Raw definition of a function returning a pointer to a function that returns an int
// and takes two constant char pointers as arguments
int (*ret_compare1(void *item))(const char *, const char *)
{
    // Unused argument - item
    return compare;
}

// More usual typedef; a Comparator2 is a pointer to a function that returns an int
// and takes two constant char pointers as arguments
typedef int (*Comparator2)(const char *, const char *);

// And ret_compare2 is a function returning a Comparator2
Comparator2 ret_compare2(void *item)
{
    // Unused argument - item
    return compare;
}

// Less usual typedef; a Comparator3 is a function that returns an int
// and takes two constant char pointers as arguments
typedef int Comparator3(const char *, const char *);

// And ret_compare3 is a function returning a pointer to a Comparator3
Comparator3 *ret_compare3(void *item)
{
    // Unused argument - item
    return compare;
}
 

Обратите внимание, что эти компараторы нельзя использовать с bsearch() и qsort() (если вы не используете довольно ужасные приведения), потому что ожидается, что эти компараторы будут принимать const void * аргументы.

Также обратите внимание, что для сравнения строк, в отличие от отдельных символов, функция, используемая qsort() или bsearch() должна быть похожа на:

 int string_comparator(const void *v1, const void *v2)
{
    const char *s1 = *(char **)v1;
    const char *s2 = *(char **)v2;
    return(strcmp(s1, s2));
}
 

Комментарии:

1. Разве аргумент функции сравнения не должен быть void *?

2. @Bruce Это та же функция сравнения, которую вы использовали в качестве примера.

3. Второй вариант typedef часто упускается из виду. Мне это нравится, потому что тогда заголовочные файлы могут объявлять функции компаратора как Comparator2 compare1; Comparator2 compare2; , что на 100% ясно, что функция предназначена для использования как Comparator2 . (Кроме того, при передаче в функцию func(Comparator2 cmp) это то же func(Comprator2 *cmp) самое, что и .)

4. @Bruce — Это зависит от API. qsort API требует int (*)(const void *, const void *) . API вашего примера кода int (*)(char *, char *) . (Гораздо более разумный) API этого ответа используется const char * для предотвращения случайного изменения значений в компараторе.

5. @Bruce: это зависит от контекста. Если вы планируете использовать компараторы со стандартными bsearch() qsort() функциями or , тогда да, аргументы должны быть const void * (и, как правило, базовое значение для сравнения строк char ** — это, а не char * ). Однако, поскольку исходная функция была int compare(char *c1, char *c2) { ... } , я сохранил тип исходной функции и добавил определитель const типа. Это будет использоваться в пользовательском коде, а не с qsort() .