jameshfisher
jameshfisher

Reputation: 36393

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

Upvotes: 4

Views: 6479

Answers (5)

DigitalRoss
DigitalRoss

Reputation: 146043

#include <stdlib.h>
#include <stdbool.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;
  return 0;
}

So there were a few side-issues clouding the core issue. Your "bool" was being interpreted as a default-int untyped parameter because the actual built-in is _Bool, humanized by the previously-missing #include <stdbool.h>. The lack of a pointer declaration for the object on the stack was confounding its ability to conform to the type of the real function object in static memory just above.

Once I included <stdbool.h>, the error shifted to "lvalue required" complaint, because there was only a function declaration and not a pointer object. The code above will compile with no warnings or errors.

Upvotes: 0

Andriy Tylychko
Andriy Tylychko

Reputation: 16256

you cannot assign to function type (int (*foo(bool))(int);), you need to use pointer to function

int (*(*foo)(bool))(int);
foo = &baz;

Upvotes: 0

TonyK
TonyK

Reputation: 17114

It's difficult to be sure, but I think this is closer to the OP's intent:

// baz is a function returning a pointer to a function
int (*baz(bool b))(int) { return b ? &abs : &inc; }

int main() {
  // foo is a pointer to a function
  int (*foo)(int) ;
  foo = baz(true); // Now foo is equal to &abs
}

Upvotes: 0

CB Bailey
CB Bailey

Reputation: 791779

This is a function declaration.

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

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

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

Upvotes: 3

rohanpm
rohanpm

Reputation: 4274

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

Upvotes: 7

Related Questions