Как объявить тип переменной указателя функции в C без использования typedef?

У меня есть функция add, которая добавляет два целых числа, как показано ниже:

int add(int a, int b){
    return a + b;
}

и я хотел создать указатель на мою функцию с именем a и вызвать мою функцию с ее помощью

printf("The sum of 45, 23: %d\n", a(45, 23));

Я сделал это, создав тип для своей функции с помощью typedef.

typedef int (*Aptr) (int, int);

Aptr a = &add;

printf("The sum of 45, 23: %d\n", a(45, 23));
The sum of 45, 23: 68

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

int (*Aptr) (int, int) a = &add;
int (*) (int, int) a = &add;

Для обоих случаев:

[Error] 'a' undeclared (first use in this function)
[Note] each undeclared identifier is reported only once for each function it appears in
[Warning] implicit declaration of function 'a' [-Wimplicit-function-declaration]

Есть ли другой способ указать тип данных функции для указателя функции?

int(*a) (int, int) = &add;
WhozCraig 10.07.2024 21:37

Почему вы хотите сделать это без typedef? Как вы заметили, сложно расписывать это полностью. typedef упрощает это.

Barmar 10.07.2024 21:42

Обратите внимание, что & перед add является лишним. Строка int (*Aptr) (int, int); a = &add; объявляет переменную Aptr типа указателя на функцию и присваивает указатель на функцию для add переменной a, которая, вероятно, не определена. Должно быть написано: int (*a) (int, int) = add; (хотя &add допустимо, как и *add, **add и другие бессмысленные декораторы). Первая часть строки int (*) (int, int); a = &add; бессмысленна — это объявление без имени объявленного объекта. Его можно было бы использовать в гипсе, но это все.

Jonathan Leffler 10.07.2024 21:47

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

John Bollinger 10.07.2024 22:42

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

Jonathan Leffler 11.07.2024 00:11
Стоит ли изучать 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
101
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Я сделал это, создав тип для своей функции с помощью typedef.

Придирка: вы сделали это, используя typedef для объявления псевдонима типа функции. Это не создает тип.

Если целью typedef является просто создание нового имени для существующего типа данных, почему это не работает?

Потому что ты делаешь это неправильно.

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

int (*Aptr) (int, int);

Вы, конечно, можете выбрать другой идентификатор:

int (*a) (int, int);

Каждый из них объявляет указатель на функцию, имеющую два параметра типа int и возвращающую int.

Этот вариант:

int (*Aptr) (int, int); a = &add;

содержит как декларацию (int (*Aptr) (int, int);), так и оператор (a = &add;). Первый вариант — вполне допустимое объявление Aptr как указателя на функцию, как уже обсуждалось. Часть после первой точки с запятой выделена отдельно, это попытка присвоить значение необъявленной переменной a.

Этот вариант:

int (*) (int, int); a = &add;

похоже, но немного дальше. int (*) (int, int) — допустимое имя типа, и его можно использовать в этой форме в приведении типов, но чтобы объявить переменную этого типа, вам нужно поместить имя переменной в соответствующую точку внутри. Форма, которую вы хотите:

int (*a) (int, int) = &add;

или альтернативно,

int (*a) (int, int);
a = &add;

или любое из вышеперечисленных значений без &, что необязательно (но не неправильно), когда add идентифицирует функцию.

Без определения типа:

int (*a)(int, int) = func;

С typedef (два метода):

typedef int func_type(int,int);
typedef int (*func_ptr_type)(int, int);

func_type *fptr = func;
func_ptr_type fptr= func;

Где func — функция, принимающая два параметра int и возвращающая int


Если целью typedef является просто создание нового имени для существующего тип данных, почему это не работает?

int (*Aptr) (int, int); a = &add;
int (*) (int, int); a = &add;

И то, и другое не имеет смысла. Второй можно записать как int (*) (int, int) a = &add;, но язык C не поддерживает этот синтаксис (правда, я не знаю почему — по моему мнению, так и должно быть ради последовательности). int (*)(int, int) можно использовать в приведениях, но не в объявлениях

В C23 и выше вы можете использовать typeof:

typeof(add) *a = add;

Когда typeof в качестве операнда передается тип функции, результатом является тип функции, а не тип указателя функции. См. также: Эквивалентны ли эти два объявления указателей функций?

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