Предупреждение при использовании указателей функций в C

На самом деле это некритичный вопрос, но я получаю это предупреждение большую часть времени, когда использую указатели на функции, и до сих пор не могу понять, почему самостоятельно. Рассмотрим следующий прототип:

typedef void * Pointer;
void tree_destroyLineage(Tree greatest_parent, void *dataDestructor(Pointer data));

И пока я могу скомпилировать свой код длиной в тысячу строк и получить ноль предупреждений. Итак, я предполагаю, что написал декларацию правильно. Но затем я вызываю его в коде, передавая бесплатно в качестве деструктора, поскольку данные, хранящиеся в узлах дерева, представляют собой простые структуры:

tree_destroyLineage(decision_tree, free);

И это заставляет меня получить сообщение "warning: passing argument 2 of 'tree_destroyLineage' from incompatible pointer type". Моя первая гипотеза заключалась в том, что компилятор не мог понять во время компиляции, что Pointer и void * — это одно и то же, поэтому я попытался создать другую функцию с точно такими же типами указателя функции, который «повторно передает» вызов free() и изменить объявление указателя функции принимает void * вместо указателя. Оба подхода дали мне одно и то же предупреждение в одном и том же месте.

Что я делаю неправильно и как это решить?


person Rafael Almeida    schedule 08.05.2009    source источник
comment
Ваше использование typedef для указателя действительно глупо. Просто используйте void *.   -  person Zifre    schedule 08.05.2009
comment
Мне много раз говорили, что... до сих пор не изменил его, потому что мне пришлось бы изменить много существующего кода, используя время, которого у меня на самом деле нет. Кроме того, некоторые оценщики немного сопротивляются использованию void *, поэтому я просто удаляю «прозрачность». Кроме того, тип gpointer GLIB точно такой же, typedef для void *. На самом деле дело идет еще дальше и определяет gconstpointer для const void *. Кроме того, по крайней мере, как показывают мои тесты, это не решит проблему.   -  person Rafael Almeida    schedule 08.05.2009
comment
Почему так грубо? Я не нахожу это глупым... Вы умалчиваете, что указатели реализованы как void * и приближают код к естественному языку.   -  person Humphrey Bogart    schedule 08.05.2009
comment
Это просто лишний набор текста, который делает код запутанным. Любой программист на C поймет void *, но ему придется искать Pointer, чтобы понять это. Это делает код ближе к естественному языку, но код не предназначен для чтения вслух.   -  person Zifre    schedule 08.05.2009
comment
Я согласен, что это лишний набор текста, но нет смысла называть людей глупыми за их предпочтения в стиле кодирования.   -  person DevinB    schedule 08.05.2009
comment
@Beau: да, это была первоначальная идея. @Zfire: я думаю, что Pointer легко понять как общий указатель, как и люди, которые читали мой код. Я согласен с вами, что если бы я кодировал это с нуля сегодня, я бы вместо этого использовал void *. Но вы также должны согласиться с тем, что есть хорошие аргументы для обеих сторон. В третий раз сам факт, что GLIB использует это, является показателем этого.   -  person Rafael Almeida    schedule 08.05.2009
comment
Вы также можете просто использовать void tree_destroyLineage(Tree great_parent, void dataDestructor(данные указателя)); просто избавься от звезды   -  person Johannes Schaub - litb    schedule 08.05.2009
comment
Извините, если я показался вам слишком суровым из-за критики, я, вероятно, выбрал неправильные слова.   -  person Zifre    schedule 08.05.2009
comment
Спасибо, это очень мило с твоей стороны. Однако тон был не моей проблемой, а догматическим утверждением. знак равно   -  person Rafael Almeida    schedule 08.05.2009


Ответы (4)


Я считаю, что правильная подпись для такой функции, как бесплатная:

void (*freefunc)(void*)

нет

void *dataDestructor(Pointer data)
person Unknown    schedule 08.05.2009
comment
Спасибо, это решает проблему, даже если я продолжаю использовать Pointer вместо void *. После поста JF я понял, что пошло не так. - person Rafael Almeida; 08.05.2009

Я не уверен насчет вашей библиотеки, но мой free не имеет возвращаемого значения (т. е. недействителен). Он не возвращает пустой указатель.

Если вы хотите, чтобы второй аргумент был указателем на функцию, которая возвращает void и принимает в качестве аргумента указатель void, я считаю, что вы хотите:

пустота (*fn)(пустота*)

и нет

пустота *fn(пустота*)

что у вас есть.

person JF.    schedule 08.05.2009
comment
Спасибо, это заставило меня увидеть разницу. Моя функция деструктора объявлялась как void * вместо void, и это вызывало проблему. - person Rafael Almeida; 08.05.2009

void tree_destroyLineage(Tree greatest_parent, 
                          void *dataDestructor(Pointer data));

должно быть:

void tree_destroyLineage(Tree greatest_parent, 
                          void (*dataDestructor)(Pointer data));
person Community    schedule 08.05.2009

Попробуй это:

void tree_destroyLineage(Tree greatest_parent, void (*dataDestructor)(void *data));

Использование typedef для указателя void просто глупо.

Изменить: проблема в том, что без скобок вокруг *dataDestructor компилятор считает, что функция возвращает void *, а не void. Скобки сообщают компилятору, что функция возвращает void, но является указателем на функцию.

person Zifre    schedule 08.05.2009
comment
Спасибо за помощь. Как я сказал в своем ответном комментарии к своему исходному сообщению, у меня возникла идея typedeffing void * из GLIB (базовая библиотека GTK+), когда я создавал свою собственную библиотеку универсальных контейнеров. Таким образом, вы можете обвинить их и назвать их глупыми. знак равно - person Rafael Almeida; 08.05.2009
comment
Да, я тоже считаю GLib глупым :). Вся идея GLib ошибочна. Они в основном пытаются написать C++ на C. - person Zifre; 08.05.2009
comment
Конечно, имитация функциональности более нового языка в более старом нелогична, как мне сказали, но GLIB отлично справляется со своей задачей. И время — серьезный вопрос, когда у вас есть ограничение на использование только чистого C, и вы тратите свое время на реализацию тысячи типов списков, в то время как вы действительно должны сосредоточиться на том, что ваши алгоритмы гибридного жадного грубого перебора делают со всеми деревьями, которые он создает. . - person Rafael Almeida; 08.05.2009
comment
Я думаю, что некоторые части GLib глупы (например, gchar всегда точно эквивалентен char), но другие части очень полезны (например, GHashTable). - person Matthew Flaschen; 09.05.2009