Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a pointer to a function that doesn't match the requirements of the formal parameter

int valid (int x, int y) {
    return x + y;
}

int invalid (int x) {
    return x;
}

int func (int *f (int, int), int x, int y) { 
    //f is a pointer to a function taking 2 ints and returning an int
    return f(x, y);
}

int main () {
    int val = func(valid, 1, 2),
        inval = func(invalid, 1, 2); // <- 'invalid' does not match the contract 

    printf("Valid:   %d\n", val);
    printf("Invalid: %d\n", inval);

    /*  Output:
     *  Valid:   3
     *  Invalid: 1
     */
}

At the line inval = func(invalid, 1, 2);, why am I not getting a compiler error? If func expects a pointer to a function taking 2 ints and I pass a pointer to a function that takes a single int, why isn't the compiler complaining?

Also, since this is happening, what happens to the second parameter y in the invalid function?

like image 612
Andreas Grech Avatar asked May 04 '10 10:05

Andreas Grech


People also ask

Can we pass formal parameter as a pointer to function?

If you declare a formal parameter of a function as a pointer type, you are passing that parameter by its address. The pointer is copied, but not the data it points to. So, Pass By Address offers another method of allowing us to change the original argument of a function (like with Pass By Reference).

How do you pass a pointer to a function as a parameter?

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 ways are possible to pass a pointer to a function?

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

Why are pointers used in passing parameters by reference?

A pointer is a variable that holds a memory address. A reference has the same memory address as the item it references. A pointer needs to be dereferenced with * to access the memory location it points to, whereas a reference can be used directly.


2 Answers

why isn't the compiler complaining?

Maybe you need a better compiler? gcc says warning: passing argument 1 of ‘func’ from incompatible pointer type on this code.

Also, since this is happening, what happens to the second parameter y in the invalid function?

Probably what happens is that the compiler does whatever it would normally do to pass a parameter (push it on the stack, put it in a designated register, etc). Calling a function with the wrong number of parameters is undefined behavior, though, so there are no guarantees - the program could crash, or the compiler could make monkeys fly out of your nose.

like image 177
David Gelhar Avatar answered Sep 17 '22 11:09

David Gelhar


Assuming you're ignoring all the compiler warnings that this should give you, you can think about what happens like this:

Your code is attempting to call a function which takes two ints, and returns one. Depending on the calling convention the parameters might be passed in registers on the cpu or on the stack, the output probably goes to a register. The valid call works fine, everything is where it's expected. For the invalid call the same stack is set up, with the two parameters as that's what the program thinks it's calling, then the function is called.

Apparently with your platform it so happens that the solitary argument for invalid is in the same location as the first parameter for valid, so that invalid coincidentally does what you would have expected calling it properly. How the parameters are cleaned up is unspecified - if the called function is supposed to clean up the space for its parameters your stack will be fried, if the calling function cleans up then your program will possibly continue to function.

Irregardless you are invoking undefined behaviour here. Try changing func to the single parameter form

int func(int(*f)(int),x){return f(x);}

and see if both calls still work.

like image 27
Scott Wales Avatar answered Sep 17 '22 11:09

Scott Wales