Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens if I cast a function pointer, changing the number of parameters

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.

  1. 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)
  2. 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 :-).

like image 878
sleske Avatar asked Jan 22 '10 16:01

sleske


People also ask

Can you cast a function pointer?

Yes, it can. This is purpose of casting function pointers, just like usual pointers. We can cast a function pointer to another function pointer type but cannot call a function using casted pointer if the function pointer is not compatible with the function to be called.

Can we increment function pointer?

The only things you can do with a function pointer are read its value, assign its value, or call the function that it points toward. You cannot increment or decrement the address stored in a function pointer or perform any other arithmetic operations.

What happens when pointers are passed to a function?

Pass-by-pointer means to pass a pointer argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the variable to which the pointer argument points. When you use pass-by-pointer, a copy of the pointer is passed to the function.

How many different way are possible to pass a pointer to a function call?

There are three ways to pass variables to a function – pass by value, pass by pointer and pass by reference.


2 Answers

If you take a car and cast it as a hammer the compiler will take you at your word that the car is a hammer but this does not turn the car into a hammer. The compiler may be successful in using the car to drive a nail but that is implementation dependent good fortune. It is still an unwise thing to do.

like image 26
William Bell Avatar answered Sep 24 '22 06:09

William Bell


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:

  • the type of the first parameter is the same for the function and the cast pointer. If you change the function to take a pointer to string and try to print that string, you will get a nice crash, since the code will try to dereference pointer to address memory 2.
  • the calling convention used by default is for the caller to cleanup the stack. If you change the calling convention, so that the callee cleans up the stack, you will end up with the caller pushing three parameters on the stack and then the callee cleaning up (or rather attempting to) one parameter. This would likely lead to stack corruption.

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.

like image 153
Franci Penov Avatar answered Sep 25 '22 06:09

Franci Penov