Приведение указателей функций в C

Почему мне нужно удалить приведение указателя функции, чтобы использовать функцию, как показано ниже?

Это компилирует:

#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;
}

Если вы назначаете void**, вам нужно использовать malloc(1 * sizeof(void*)). Аргумент для sizeof всегда является типом назначения с одним меньше *.

Barmar 11.12.2020 23:44

@Barmar Я пытаюсь хранить функции внутри массива пустых указателей. В настоящее время это работает. Однако я пытаюсь понять, почему объявление указателя такое.

Iwata Kurosawa 11.12.2020 23:48

См. stackoverflow.com/questions/3941793/… нет гарантии, что void* может содержать указатель на функцию.

Barmar 11.12.2020 23:50

Как правило, вы не разыменовываете указатели функций.

Barmar 11.12.2020 23:50

@Barmar: Во-первых, они не должны использовать void *; указатели на функции отличаются от указателей на объекты, и void * не является универсальным типом для указателей на функции. Кроме того, предпочтительнее использовать присваиваемый фактический идентификатор с * для sizeof, а не повторять тип: AnyType *p = malloc(NumberOf * sizeof *p);.

Eric Postpischil 11.12.2020 23:51
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Объявление 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] в функцию, чтобы ее можно было вызвать.

Iwata Kurosawa 12.12.2020 00:02

В отношении указателей на объекты и функции, в чем причина этого? Это потому, что C не дает никаких надежных гарантий на его целостность во время использования?

Iwata Kurosawa 12.12.2020 00:12

@IwataKurosawa: В частности, он приводит p[0] к указателю на функцию. Оператор вызова функции (скобки после выражения) вызывает только указатели на функции. Когда вы пишете вызов функции, используя имя функции, например sin(x), функция автоматически преобразуется в указатель.

Eric Postpischil 12.12.2020 00:12

(Это верно, даже если функция создается путем разыменования указателя. Если у вас есть q, который указывает на функцию, и вы пишете (*q)(x), *q — это функция, но она автоматически преобразуется в указатель на функцию. И тогда вы можете применить * снова. (**q)(x) вызывает ту же функцию. То же самое делает (******q)(x).)

Eric Postpischil 12.12.2020 00:12

@IwataKurosawa: указатели объектов и указатели функций различаются, потому что на некоторых компьютерах их адреса управлялись по-разному, а стандарт C хотел разрешить использование C на самых разных компьютерах.

Eric Postpischil 12.12.2020 00:13

Другие вопросы по теме