Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C, assignment of function pointer to appropriately-typed variable gives "cannot convert ... in assignment"

Take the following C/C++ code:

#include <stdlib.h>

int inc(int i) { return i+1; }  // int→int, like abs()
// baz is bool→(int→int)
int (*baz(bool b))(int) { return b ? &abs : &inc; }

int main() {
  int (*foo(bool))(int);  // foo is &(bool→(int→int))
  foo = baz;
}

Attempting to compile this (gcc or g++) gives:

$ g++ test.cc
test.cc: In function ‘int main()’:
test.cc:9: error: assignment of function ‘int (* foo(bool))(int)’
test.cc:9: error: cannot convert ‘int (*(bool))(int)’ to ‘int (*(bool))(int)’ in assignment

Check for yourself: the two types it claims it cannot convert between are exactly the same. Why then is it claiming that they are incompatible?

EDIT 1: The problem disappears when using typedefs (as is recommended), like so:

int main() {
  typedef int (*int2int)(int);
  typedef int2int (*bool2_int2int)(bool);
  bool2_int2int foo;
  foo = baz;
}

EDIT 2: The compiler, of course, was right. The problem with my original code, as many pointed out, is that foo in main() is a declaration of a function, and not a function pointer. The error in the assignment was therefore not conflicting types but assigning to a function, which is not possible. The correct code is:

#include <stdlib.h>

int inc(int i) { return i+1; }  // int→int, like abs()
// baz is bool→(int→int)
int (*baz(bool b))(int) { return b ? &abs : &inc; }

int main() {
  int (*(*foo)(bool))(int);  // foo is &(bool→(int→int))
  foo = &baz;
}
like image 885
jameshfisher Avatar asked Dec 28 '22 03:12

jameshfisher


2 Answers

The code is in fact wrong. The problem is that this line:

int (*foo(bool))(int);  // foo is &(bool→(int→int))

... doesn't mean what you think it means. It's interpreted as a declaration of a function named "foo". That makes perfect sense. Think about it - if you had wanted to forward declare "baz", you would have put int (*baz(bool))(int); , right? Also, since baz is a function which returns a function pointer, and foo is a pointer to a function which returns a function pointer, wouldn't you expect the syntax to be more complicated?

You declared foo as a function of the same type as baz, rather than as a pointer to a function of same type as baz.

From your compiler, the first error message is the useful one - it tells you assignment of function, i.e. you have tried to assign to a function, which is an error.

I'm not even going to try to write the correct solution without typedefs :-) Here's some code which compiles and I think is right, using typedefs:

#include <stdlib.h>
#include <stdbool.h>

typedef int(*IntReturnsInt)(int);

int inc(int i) { return i+1; } 
IntReturnsInt baz(bool b) { return b ? &abs : &inc; }

int main() {
  IntReturnsInt (*foo)(bool b);
  foo = baz;
}

In this example the double-function-pointer concept is a bit clearer - IntReturnsInt is a function pointer type and foo is a pointer to a function which returns IntReturnsInt... phew :-)

like image 150
rohanpm Avatar answered Jan 31 '23 03:01

rohanpm


This is a function declaration.

int (*foo(bool))(int);

If you wanted to declare a function pointer, you should do:

int (*(*foo)(bool))(int);
like image 35
CB Bailey Avatar answered Jan 31 '23 05:01

CB Bailey