3

I'm trying to make sure I understand the syntax for function pointers in C. I know it's just a pointer to a specific type. That being said, why does the following code compile and print '10'?

(Note I'm using GCC 9.4.0 on Ubuntu 20.04)

void f(int);
void (*foo)() = f;

int main(){
   foo(10);
   return 0;
}

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

Shouldn't we at least get a compile time warning: initialization of 'void(*)()' with incompatible pointer type 'void(*)(int)'? Is foo getting initialized to void(*)(int) based on f?

If I change 'void f(int)' to 'void f(float)' I do get a warning. If I add 3 more int params to f e.g. void f(int, int, int, int) it still compiles and runs fine. If I make the last param a float, another warning.

svs29122
  • 43
  • 4
  • Because `foo` is defined to be a pointer to a function whose arguments are not declared so it will allow any function whose return type is `void`. Try using `void (*foo)(void) = f;` and you'll see a warning. – Richard Chambers Feb 01 '23 at 03:31
  • 1
    As a side note, this is obsolescent C since year 1989. Empty parenthesis `()` no prototype style should not be used. And it will finally get removed in upcoming C23. – Lundin Feb 01 '23 at 07:36
  • @Lundin What's the rationale behind that decision? – Mehdi Charife Jun 26 '23 at 23:21
  • 1
    @MehdiCharife Non-prototype functions aren't type safe and therefore wildly dangerous. To clarify, empty parenthesis in C23 will not mean non-prototype function declaration but instead it will mean `void` just like C++ has always worked. – Lundin Jun 28 '23 at 11:18

2 Answers2

4

The type of the function pointer foo:

void (*foo)()

Is a pointer to a function taking an unspecified number of parameters and returning void. So a pointer to any function that has a return type of void (assuming no parameters are subject to promotion, i.e. char, short, float) is compatible with foo and can be assigned to it.

If you instead defined it like this:

void (*foo)(void)

This would generate an error for an incompatible pointer type, as foo points to a function that takes no arguments and returns void, and f does not match that.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Is this applicable when defining a function that takes a function pointer as an argument? Can you define a function taking e.g. `int (*f)()` as an argument and then pass an `int (*f)(int, float)` to it? – Mehdi Charife Jun 26 '23 at 22:37
2

The rules are the same for function pointer declarations as for function declarations ; and a pointer to function with empty parentheses parameter list is compatible with a pointer to prototyped function, if the return type matches.

In your example the issues are equivalent to:

void g();

int main()
{
    g(10);
}

void g(int) { ..... }

The rules are: you can declare a function with empty parentheses and call it with arguments, but in the function call, certain conditions must be met and it is undefined behaviour with no diagnostic required if those conditions are not met.

One of the "certain conditions" is that you cannot have float as a parameter type in the function definition. Another is that the type and count of arguments must match the type and count of parameters in the function definition. To repeat, no diagnostic is required for any of this; your compiler is going above minimum requirements by warning about the incorrect parameter type float.

M.M
  • 138,810
  • 21
  • 208
  • 365