I’m just beginning to wrap my head around function pointers in C. To understand how casting of function pointers works, I wrote the following program. It basically creates a function pointer to a function that takes one parameter, casts it to a function pointer with three parameters, and calls the function, supplying three parameters. I was curious what would happen:
#include <stdio.h>
int square(int val){
return val*val;
}
void printit(void* ptr){
int (*fptr)(int,int,int) = (int (*)(int,int,int)) (ptr);
printf("Call function with parameters 2,4,8.\n");
printf("Result: %d\n", fptr(2,4,8));
}
int main(void)
{
printit(square);
return 0;
}
This compiles and runs without errors or warnings (gcc -Wall on Linux / x86). The output on my system is:
Call function with parameters 2,4,8.
Result: 4
So apparently the superfluous arguments are simply silently discarded.
Now I’d like to understand what is really happening here.
- As to legality: If I understand the answer to Casting a function pointer to another type correctly, this is simply undefined behaviour. So the fact that this runs and produces a reasonable result is just pure luck, correct? (or niceness on the part of the compiler writers)
- Why will gcc not warn me of this, even with Wall? Is this something the compiler just cannot detect? Why?
I’m coming from Java, where typechecking is a lot stricter, so this behaviour confused me a bit. Maybe I’m experiencing a cultural shock :-).
The extra parameters are not discarded. They are properly placed on the stack, as if the call is made to a function that expects three parameters. However, since your function cares about one parameter only, it looks only at the top of the stack and does not touch the other parameters.
The fact that this call worked is pure luck, based on the two facts:
There is no way the compiler can warn you about potential problems like this for one simple reason – in the general case, it does not know the value of the pointer at compile time, so it can’t evaluate what it points to. Imagine that the function pointer points to a method in a class virtual table that is created at runtime? So, it you tell the compiler it is a pointer to a function with three parameters, the compiler will believe you.