Lance Pollard
Lance Pollard

Reputation: 79450

How do I pass a function as a parameter to a function in C, if the passed function also takes functions as parameters?

So this simple case just prints out 3 when passing a function:

#include <stdio.h>

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

int
case_1_fn_a(int fn_x(int, int)) {
  return fn_x(1, 2);
}

int
main() {
  int x = case_1_fn_a(add);
  printf("%d\n", x);
  return 0;
}

But now I would like to pass a function to a function. How do I do that?

#include <stdio.h>

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

int
case_2_fn_a(int fn_x(int, int), int fn_y(int, int)) {
  return add(fn_x(add, add), fn_y(add, add));
}

int
case_2_fn_b(int fn_x(int, int)) {
  return fn_x(1, 2);
}

int
main() {
  int x = case_2_fn_a(case_2_fn_b, case_2_fn_b);
  printf("%d\n", x);
  return 0;
}

But I get these errors (I get all kinds of different errors if I try adjusting this or that thing, so nothing works):

tmp.c:11:19: warning: incompatible pointer to integer conversion passing 'int (int, int)' to parameter of type 'int' [-Wint-conversion]
  return add(fn_x(add, add), fn_y(add, add));
                  ^~~
tmp.c:11:24: warning: incompatible pointer to integer conversion passing 'int (int, int)' to parameter of type 'int' [-Wint-conversion]
  return add(fn_x(add, add), fn_y(add, add));
                       ^~~
tmp.c:11:35: warning: incompatible pointer to integer conversion passing 'int (int, int)' to parameter of type 'int' [-Wint-conversion]
  return add(fn_x(add, add), fn_y(add, add));
                                  ^~~
tmp.c:11:40: warning: incompatible pointer to integer conversion passing 'int (int, int)' to parameter of type 'int' [-Wint-conversion]
  return add(fn_x(add, add), fn_y(add, add));
                                       ^~~
tmp.c:21:23: warning: incompatible pointer types passing 'int (int (*)(int, int))' to parameter of type 'int (*)(int, int)'
      [-Wincompatible-pointer-types]
  int x = case_2_fn_a(case_2_fn_b, case_2_fn_b);
                      ^~~~~~~~~~~
tmp.c:10:17: note: passing argument to parameter 'fn_x' here
case_2_fn_a(int fn_x(int, int), int fn_y(int, int)) {
                ^
tmp.c:21:36: warning: incompatible pointer types passing 'int (int (*)(int, int))' to parameter of type 'int (*)(int, int)'
      [-Wincompatible-pointer-types]
  int x = case_2_fn_a(case_2_fn_b, case_2_fn_b);
                                   ^~~~~~~~~~~
tmp.c:10:37: note: passing argument to parameter 'fn_y' here
case_2_fn_a(int fn_x(int, int), int fn_y(int, int)) {
                                    ^
6 warnings generated.
Segmentation fault: 11

Essentially I want to pass a series of functions to function "A", and then have function "A" take those functions (let's call them functions "B", "C", and "D"), and call them with a few functions as parameters. Functions "B", "C" and "D" then take their function arguments, and pass simple values to them like integers or chars.

Upvotes: 3

Views: 81

Answers (2)

dbush
dbush

Reputation: 224892

First, when passing functions as parameters, you typically want to use function pointers instead. So instead of this as a parameter:

int fn_x(int, int)

You would use this:

int (*fn_x)(int, int)

Now for the main problem: functions (and function pointers) as parameters and return values can have confusing syntax. Creating typedefs for function pointers greatly simplifies this.

So let's make the following typedefs:

typedef int (*addfunc)(int, int);
typedef int (*fnb)(addfunc);
typedef int (*fna)(fnb, fnb);

So now you have:

int
case_2_fn_a(fnb fn_x, fnb fn_y) {
  return add(fn_x(add), fn_y(add));
}

int
case_2_fn_b(addfunc fn_x) {
  return fn_x(1, 2);
}

As you can see, the syntax is much cleaner. It's also more apparent that the body of case_2_fn_a had a error where fn_x and fn_y were being passed two parameters instead of one.

If you really wanted to do this without typedefs, case_2_fn_a would look like this:

int
case_2_fn_a(int (*fn_x)(int (*)(int,int)), int (*fn_y)(int (*)(int,int))) {

  return add(fn_x(add), fn_y(add));
}

Upvotes: 5

Jona
Jona

Reputation: 1286

As said in the comments, use function pointers:

Case 1:

#include <stdio.h>

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

int
case_1_fn_a(int(*fn_x)()) {
  return (*fn_x)(1, 2);
}

int
main() {
  int x = case_1_fn_a(&add);
  printf("%d\n", x);
  return 0;
} 

Case 2:

#include <stdio.h>

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

int
case_2_fn_a(int (*fn_x)(), int(*fn_y)()) {
  return add((*fn_x)(&add), (*fn_y)(&add));
}

int
case_2_fn_b(int(*fn_x)()) {
  return (*fn_x)(1, 2);
}

int
main() {
  int x = case_2_fn_a(&case_2_fn_b, &case_2_fn_b);
  printf("%d\n", x);
  return 0;
}

Upvotes: 2

Related Questions