Почему мне нужно удалить приведение указателя функции, чтобы использовать функцию, как показано ниже?
Это компилирует:
#include <stdio.h>
int print_int(int i){
printf("%d", i);
return i;
}
typedef int (*print_int_func) (int);
int main(){
void** p = malloc(1*sizeof(print_int_func*));
p[0] = (print_int_func*)print_int;
((print_int_func)p[0])(2); // This Compiles
((print_int_func*)p[0])(2); // This does NOT
return 0;
}
@Barmar Я пытаюсь хранить функции внутри массива пустых указателей. В настоящее время это работает. Однако я пытаюсь понять, почему объявление указателя такое.
См. stackoverflow.com/questions/3941793/… нет гарантии, что void*
может содержать указатель на функцию.
Как правило, вы не разыменовываете указатели функций.
@Barmar: Во-первых, они не должны использовать void *
; указатели на функции отличаются от указателей на объекты, и void *
не является универсальным типом для указателей на функции. Кроме того, предпочтительнее использовать присваиваемый фактический идентификатор с *
для sizeof
, а не повторять тип: AnyType *p = malloc(NumberOf * sizeof *p);
.
Объявление typedef int (*print_int_func) (int);
объявляет print_int_func
указателем на определенный тип функции. Итак, (print_int_func)p[0]
приводит p[0]
к такому указателю на функцию, но (print_int_func*)p[0]
приводит p[0]
к указателю на указатель на функцию. Таким образом, результатом является указатель на объект (этот объект является указателем на функцию). Поскольку это объект, а не функция (или указатель на функцию), его нельзя вызывать как функцию.
Кроме того, избегайте использования void *
для указателей на функции. void *
— это указатель на объект, а стандарт C не определяет преобразования между указателями на объекты и указателями на функции. Чтобы создать «общий» указатель на функцию, просто выберите любой тип функции и используйте указатель на этот тип:
Например, вы можете объявить произвольный тип:
typedef void (*CommonFunctionPointer)(void);
и сделать из них массив:
CommonFunctionPointer *p = malloc(N * sizeof *p);
,
а затем вы можете сохранить любой указатель функции в массиве:
p[i] = (CommonFunctionPointer) print_int;
и используйте указатель из массива, вернув его к правильному типу:
((int (*)(int)) p[i])(2);
.
Спасибо ! Итак, (print_int_func)p[0]
переводит p[0] в функцию, чтобы ее можно было вызвать.
В отношении указателей на объекты и функции, в чем причина этого? Это потому, что C не дает никаких надежных гарантий на его целостность во время использования?
@IwataKurosawa: В частности, он приводит p[0]
к указателю на функцию. Оператор вызова функции (скобки после выражения) вызывает только указатели на функции. Когда вы пишете вызов функции, используя имя функции, например sin(x)
, функция автоматически преобразуется в указатель.
(Это верно, даже если функция создается путем разыменования указателя. Если у вас есть q
, который указывает на функцию, и вы пишете (*q)(x)
, *q
— это функция, но она автоматически преобразуется в указатель на функцию. И тогда вы можете применить *
снова. (**q)(x)
вызывает ту же функцию. То же самое делает (******q)(x)
.)
@IwataKurosawa: указатели объектов и указатели функций различаются, потому что на некоторых компьютерах их адреса управлялись по-разному, а стандарт C хотел разрешить использование C на самых разных компьютерах.
Если вы назначаете
void**
, вам нужно использоватьmalloc(1 * sizeof(void*))
. Аргумент дляsizeof
всегда является типом назначения с одним меньше*
.