Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
424 views
in Technique[技术] by (71.8m points)

c - 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.
");
  printf("Result: %d
", 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 :-).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...