C에서 함수를 매개 변수로 어떻게 전달합니까?


616

일련의 데이터에서 매개 변수가 전달한 함수를 수행하는 함수를 만들고 싶습니다. C에서 함수를 매개 변수로 어떻게 전달합니까?


12
함수 / 배열을 변수로 사용하는 경우 항상을 사용하십시오 typedef.
Mooing Duck

3
우리는 그것을 호출 기능 포인터
AminM

함수 이름은 함수의 후원자 여야합니다. C를 배우는 대부분의 사람들은 조만간 qsort를 다루는데 정확히 이것을 수행합니까?
mckenzm

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) );

이것은 매개 변수 fvoid리턴 유형 을 가지며 단일 int매개 변수 를 취하는 함수에 대한 포인터가된다고 표시합니다 . 다음 함수 ( print)는 func올바른 유형이므로 매개 변수로 전달 될 수있는 함수의 예입니다 .

void print ( int x ) {
  printf("%d\n", x);
}

함수 호출

함수 매개 변수로 함수를 호출 할 때 전달 된 값은 함수에 대한 포인터 여야합니다. 이를 위해 함수 이름 (괄호없이)을 사용하십시오.

func(print);

func인쇄 함수를 전달하여 호출 합니다.

기능 바디

다른 매개 변수와 마찬가지로 func이제 함수 본문에서 매개 변수 이름을 사용하여 매개 변수 값에 액세스 할 수 있습니다. func0-4에 전달 된 함수를 적용 한다고 가정 해 봅시다 . 먼저 루프가 print를 직접 호출하는 모습을 고려하십시오.

for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
  print(ctr);
}

func의 매개 변수 선언은 그것이 f원하는 함수에 대한 포인터의 이름 이라고 말하고 있기 때문에 f, 포인터라면 포인터 *ff가리키는 것 (즉, print이 경우 함수) 임을 먼저 상기합니다 . 결과적으로 위의 루프에서 인쇄가 발생할 때마다 *f다음 과 같이 바꿉니다 .

void func ( void (*f)(int) ) {
  for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
    (*f)(ctr);
  }
}

출처


40
첫 번째 및 마지막 코드 예제에서 *는 필수가 아닙니다. 함수 매개 변수 정의와 f함수 호출 모두 f*없이 그대로 사용할 수 있습니다 . 그러나 매개 변수 f가 함수 포인터라는 것을 분명히하기 위해 수행하는 것이 좋습니다. 그러나 가독성이 자주 손상됩니다.
Gauthier

5
예는 [c99, 6.9.1§14]를 참조하십시오. 둘 다 물론 맞습니다. 방금 대안을 언급하고 싶었습니다.
Gauthier

6
정말? 최상위 답변은 typedeffor 함수 포인터 사용에 대한 단일 참조를 만들지 않습니까? 죄송합니다. 투표해야합니다.
Jonathon Reinhart 8

3
@ JonathonReinhart, 'typedef'apprach의 장점은 무엇입니까? 이 버전은 훨씬 더 깔끔해 보이고 추가 설명이 없습니다. 여기에 거의 초보자가 있습니다.
Abhinav Gauniyal

3
@JonathonReinhart는 잘 발견되었습니다. 포인터 typedef는 코드를 난독 처리하므로 사용해서는 안됩니다.
MM

129

이 질문에는 이미 함수 포인터를 정의하는 대답이 있지만 특히 응용 프로그램 주위에 전달할 경우 매우 혼란 스러울 수 있습니다. 이 불쾌감을 피하기 위해 함수 포인터를 더 읽기 쉬운 것으로 typedef하는 것이 좋습니다. 예를 들어.

typedef void (*functiontype)();

void를 반환하고 인수를받지 않는 함수를 선언합니다. 이 유형에 대한 함수 포인터를 작성하려면 다음을 수행하십시오.

void dosomething() { }

functiontype func = &dosomething;
func();

int를 반환하고 char을 취하는 함수의 경우

typedef int (*functiontype2)(char);

그것을 사용하기 위해

int dosomethingwithchar(char a) { return 1; }

functiontype2 func2 = &dosomethingwithchar
int result = func2('a');

함수 포인터를 읽기 쉬운 형식으로 바꾸는 데 도움이되는 라이브러리가 있습니다. 부스트 기능 라이브러리는 위대하고 잘 노력 가치가 있습니다!

boost::function<int (char a)> functiontype2;

위의 것보다 훨씬 좋습니다.


4
"함수 포인터를 유형으로 바꾸려면"부스트 라이브러리가 필요하지 않습니다. 그냥 사용하십시오 typedef; 더 간단하고 추가 라이브러리가 필요하지 않습니다.
wizzwizz4

72

C ++ 11부터는 기능 라이브러리 를 사용하여 간결하고 일반적인 방식으로이 작업을 수행 할 수 있습니다 . 구문은 예를 들어

std::function<bool (int)>

여기서 bool첫 번째 인수가 유형 인 1 인수 함수의 리턴 유형 int입니다.

아래에 예제 프로그램이 포함되어 있습니다.

// g++ test.cpp --std=c++11
#include <functional>

double Combiner(double a, double b, std::function<double (double,double)> func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

그러나 때로는 템플릿 함수를 사용하는 것이 더 편리합니다.

// g++ test.cpp --std=c++11

template<class T>
double Combiner(double a, double b, T func){
  return func(a,b);
}

double Add(double a, double b){
  return a+b;
}

double Mult(double a, double b){
  return a*b;
}

int main(){
  Combiner(12,13,Add);
  Combiner(12,13,Mult);
}

43
문제는 C에 관한 것입니다. C ++은 여기에 적용되지 않습니다.
Super Cat

16
C ++ ( stackoverflow.com/questions/6339970/… )에 대한 질문 이 여기에 언급되어 있으므로이 답변이 적절하다고 생각합니다.
mr_T

8
이 질문에 대한 답이 C이므로 C ++에 대한 질문을 여기에 언급해서는 안됩니다.
Michael Fulton

5
이 질문은 "c ++ 함수 호출을 매개 변수로"검색했을 때 처음으로 나타 났으 므로이 대답은 여기에 관계없이 목적에 잘 부합합니다.
ufoxDan

25

합격 다른 함수 매개 변수 함수의 주소를 아래와 같이

#include <stdio.h>

void print();
void execute(void());

int main()
{
    execute(print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void f()) // receive address of print
{
    f();
}

또한 함수 포인터를 사용하여 함수 를 매개 변수로 전달할 수 있습니다

#include <stdio.h>

void print();
void execute(void (*f)());

int main()
{
    execute(&print); // sends address of print
    return 0;
}

void print()
{
    printf("Hello!");
}

void execute(void (*f)()) // receive address of print
{
    f();
}

1
모든 것을 이해할 수없는 엉망으로 자르는 대신 전체 코드 블록으로 아주 좋은 대답. 두 기술의 차이점에 대해 자세히 설명해 주시겠습니까?
라파엘 Eyng

5

기능에 따라, 함수 포인터로 "전달"할 수 있습니다 ISO C11 6.7.6.3p8 : " ''기능 반환 형식 포인터 ''로 조정해야한다 ''기능 유형을 반환 '과 같은 매개 변수의 선언 , 6.3에서와 같이 .2.1. ". 예를 들면 다음과 같습니다.

void foo(int bar(int, int));

이것과 같습니다 :

void foo(int (*bar)(int, int));

어떤 문서를 인용하고 있습니까? 그것에 대한 링크가 있습니까?
Rafael Eyng

1
ISO C11 표준에서 인용하고 있습니다.
doppelheathen


-2

실제로는 기능이 아니지만 지역화 된 코드입니다. 물론 결과 만 코드를 전달하지는 않습니다. 이벤트 디스패처로 전달되어 나중에 실행될 수 있도록 작동하지 않습니다 (이벤트가 발생할 때가 아니라 결과가 지금 계산되므로). 그러나 그것이 당신이하려는 모든 것이라면 코드를 한 곳으로 현지화합니다.

#include <stdio.h>

int IncMultInt(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; } ) );

    return 0;
}

방금 함수를 호출하고 있습니다. 대신 다른 기능을 어떻게 전달 IncMultInt하겠습니까?
Tejas Pendse
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.