Имя функции должно быть знаком с функцией. Большинство людей, изучающих C, рано или поздно изучают qsort, что делает именно это?
Маккензм
5
@ MooingDuck Я не согласен с вашим предложением, и в вашем предложении нет аргументов в поддержку этого вывода. Лично я предпочитаю никогда не использовать typedef для указателей на функции, и я думаю, что это делает код более понятным и легким для чтения.
andrewrk
2
@andrewrk: Вы предпочитаете void funcA(void(*funcB)(int))и void (*funcA())()к typedef void funcB(); void funcA(funcB)и funcB funcA()? Я не вижу преимущества.
Mooing Duck
Ответы:
747
декларация
Прототип функции, которая принимает параметр функции, выглядит следующим образом:
void func (void(*f)(int));
Это говорит о том, что параметр fбудет указателем на функцию, которая имеет voidтип возвращаемого значения и которая принимает один intпараметр. Следующая функция ( print) является примером функции, которую можно передать funcкак параметр, потому что это правильный тип:
void print (int x ){
printf("%d\n", x);}
Вызов функции
При вызове функции с параметром функции передаваемое значение должно быть указателем на функцию. Используйте имя функции (без скобок) для этого:
func(print);
будет вызывать func, передавая ему функцию печати.
Тело функции
Как и любой параметр, funcтеперь можно использовать имя параметра в теле функции для доступа к значению параметра. Допустим, что funcк функции будет применено переданное ей число 0-4. Сначала рассмотрим, как будет выглядеть цикл для непосредственного вызова print:
for(int ctr =0; ctr <5; ctr++){
print(ctr);}
Так funcкак объявление параметра говорит, что fэто имя для указателя на желаемую функцию, мы сначала напомним, что если fэто указатель, то *fэто то, на что fуказывает (то есть функция printв данном случае). В результате просто замените все вхождения print в цикле выше на *f:
В вашем первом и последнем примерах кода * не является обязательным. Как определение параметра функции, так и fвызов функции могут быть fтакими же, как и без *. Возможно, было бы неплохо сделать это так, как вы, чтобы было очевидно, что параметр f является указателем на функцию. Но это часто ухудшает читабельность.
Готье
5
См. [C99, 6.9.1§14] для примеров. И то и другое верно, я просто хотел упомянуть альтернативу.
Готье
6
В самом деле? Ответ с наивысшим рейтингом не содержит ни одной ссылки на использование typedefуказателей для функции? Извините, надо понизить голосование.
Джонатон Рейнхарт
3
@JonathonReinhart, какие преимущества дает apprach typedef? Хотя эта версия выглядит намного чище и лишена дополнительных утверждений. здесь довольно много.
Абхинав Гауниал
3
@JonathonReinhart хорошо заметили; Следует четко отметить, что указатели typedefs запутывают код и поэтому не должны использоваться.
ММ
128
На этот вопрос уже есть ответ для определения указателей на функции, однако они могут стать очень запутанными, особенно если вы собираетесь передавать их по своему приложению. Чтобы избежать этой неприятности, я бы порекомендовал вам ввести указатель функции во что-то более читабельное. Например.
typedefvoid(*functiontype)();
Объявляет функцию, которая возвращает void и не принимает аргументов. Чтобы создать указатель на функцию этого типа, теперь вы можете сделать:
Для функции, которая возвращает int и принимает символ, вы бы сделали
typedefint(*functiontype2)(char);
и использовать это
int dosomethingwithchar(char a){return1;}
functiontype2 func2 =&dosomethingwithcharint result = func2('a');
Существуют библиотеки, которые могут помочь превратить указатели функций в удобные для чтения типы. Библиотека функций буста великолепна и стоит затраченных усилий!
Если вы хотите «превратить указатель функции в тип», вам не нужна библиотека boost. Просто используйте typedef; это проще и не требует дополнительных библиотек.
wizzwizz4
73
Начиная с C ++ 11 вы можете использовать функциональную библиотеку, чтобы сделать это кратко и обобщенно. Синтаксис, например,
std::function<bool(int)>
где boolздесь возвращаемый тип функции с одним аргументом, первый аргумент которой имеет тип int.
Очень хороший ответ, с целыми блоками кода (вместо того, чтобы нарезать все в непонятный беспорядок). Не могли бы вы рассказать о различиях обеих техник?
Рафаэль Эйнг
5
Функции могут быть «переданы» как указатели на функции, в соответствии с ISO C11 6.7.6.3p8: « Объявление параметра как« функции, возвращающего тип »должно быть настроено на« указатель на функцию, возвращающую тип » , как в 6.3 .2.1. " Например, это:
На самом деле это не функция, а локализованный фрагмент кода. Конечно, он не передает код только результат. Он не будет работать, если он будет передан диспетчеру событий для запуска в более позднее время (так как результат рассчитывается сейчас, а не когда происходит событие). Но он локализует ваш код в одном месте, если это все, что вы пытаетесь сделать.
#include<stdio.h>intIncMultInt(int a,int b){
a++;return a * b;}int main(int argc,char*argv[]){int a =5;int b =7;
printf("%d * %d = %d\n", a, b,IncMultInt(a, b));
b =9;// Create some local code with it's own local variable
printf("%d * %d = %d\n", a, b,({int _a = a+1; _a * b;}));return0;}
typedef
.void funcA(void(*funcB)(int))
иvoid (*funcA())()
кtypedef void funcB(); void funcA(funcB)
иfuncB funcA()
? Я не вижу преимущества.Ответы:
декларация
Прототип функции, которая принимает параметр функции, выглядит следующим образом:
Это говорит о том, что параметр
f
будет указателем на функцию, которая имеетvoid
тип возвращаемого значения и которая принимает одинint
параметр. Следующая функция (print
) является примером функции, которую можно передатьfunc
как параметр, потому что это правильный тип:Вызов функции
При вызове функции с параметром функции передаваемое значение должно быть указателем на функцию. Используйте имя функции (без скобок) для этого:
будет вызывать
func
, передавая ему функцию печати.Тело функции
Как и любой параметр,
func
теперь можно использовать имя параметра в теле функции для доступа к значению параметра. Допустим, чтоfunc
к функции будет применено переданное ей число 0-4. Сначала рассмотрим, как будет выглядеть цикл для непосредственного вызова print:Так
func
как объявление параметра говорит, чтоf
это имя для указателя на желаемую функцию, мы сначала напомним, что еслиf
это указатель, то*f
это то, на чтоf
указывает (то есть функцияprint
в данном случае). В результате просто замените все вхождения print в цикле выше на*f
:Источник
источник
f
вызов функции могут бытьf
такими же, как и без *. Возможно, было бы неплохо сделать это так, как вы, чтобы было очевидно, что параметр f является указателем на функцию. Но это часто ухудшает читабельность.typedef
указателей для функции? Извините, надо понизить голосование.На этот вопрос уже есть ответ для определения указателей на функции, однако они могут стать очень запутанными, особенно если вы собираетесь передавать их по своему приложению. Чтобы избежать этой неприятности, я бы порекомендовал вам ввести указатель функции во что-то более читабельное. Например.
Объявляет функцию, которая возвращает void и не принимает аргументов. Чтобы создать указатель на функцию этого типа, теперь вы можете сделать:
Для функции, которая возвращает int и принимает символ, вы бы сделали
и использовать это
Существуют библиотеки, которые могут помочь превратить указатели функций в удобные для чтения типы. Библиотека функций буста великолепна и стоит затраченных усилий!
это намного приятнее, чем выше.
источник
typedef
; это проще и не требует дополнительных библиотек.Начиная с C ++ 11 вы можете использовать функциональную библиотеку, чтобы сделать это кратко и обобщенно. Синтаксис, например,
где
bool
здесь возвращаемый тип функции с одним аргументом, первый аргумент которой имеет типint
.Я включил пример программы ниже:
Однако иногда удобнее использовать функцию шаблона:
источник
Передать адрес функции в качестве параметра другой функции, как показано ниже
Также мы можем передать функцию в качестве параметра, используя указатель на функцию
источник
Функции могут быть «переданы» как указатели на функции, в соответствии с ISO C11 6.7.6.3p8: « Объявление параметра как« функции, возвращающего тип »должно быть настроено на« указатель на функцию, возвращающую тип » , как в 6.3 .2.1. " Например, это:
эквивалентно этому:
источник
Вам нужно передать указатель на функцию . Синтаксис немного громоздкий, но он становится действительно мощным, когда вы с ним познакомитесь.
источник
На самом деле это не функция, а локализованный фрагмент кода. Конечно, он не передает код только результат. Он не будет работать, если он будет передан диспетчеру событий для запуска в более позднее время (так как результат рассчитывается сейчас, а не когда происходит событие). Но он локализует ваш код в одном месте, если это все, что вы пытаетесь сделать.
источник
IncMultInt
?