-4

I am trying to understand what is a pointer to a function in c.

I am wanting some detailed process of calling a pointer to function, thus, i could understand pointer to function better.

Could somebody explain why does my code below not crash and have some wired output? To narrow down, I am seeking something like javap which could explain how does jdk compile my code and jvm run my code

  1. what is the relationship of a void return and number 14,15 or 16. (the void function return)
  2. is there any security problem to my second param or is it same as non-init val ?

test.c

#include <stdio.h>
#include <stdlib.h>


static void f(int x, int y){

    printf("x = %d \n",  x );
    printf("y = %d \n",  y );
}

typedef int (*FUNC)(int);

int main(void){

    long int addr = (long int)f;
    printf("%d \n",  (int)((FUNC)addr)(1) );

    return 0;
}

output on mac os compiled with i686-apple-darwin11-llvm-gcc-4.2

x = 1 
y = 1479046720 
16 
farmer1992
  • 7,816
  • 3
  • 30
  • 26
  • A pointer to a function is just a way to store a reference to a function in a variable, so you can call that function later. Because it is a variable, and not a fixed call, you can possibly change what function to call at runtime, but that's it. There is no magic involved. – Bo Persson Feb 03 '13 at 12:26
  • see http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work – farmer1992 Feb 07 '15 at 22:12

4 Answers4

4

The answer is undefined behavior. You're using two incompatible function pointer types and use one to call the other. (Not to mention storing the pointer in an integer, etc., etc.) Thus, your program invokes undefined behavior, and as such, anything can happen. And the values you get are most probably just random crap from the messed up stack and/or CPU registers.

3

You are causing undefined behavior all over the place:

  • You're storing the function pointer in a integer, which isn't guaranteed to work
  • You're casting said integer to a different type of function pointer (fewer parameters) with a different return type
  • You're calling the function with fewer parameters than it expects
  • You take a return value from a function returning void

Trying to make sense of this is just unreasonable, but as a guess since you're using x86:

  • x is populated correctly in the function with the 1 you passed
  • y isn't so it gets a random value, likely some leftover on the stack
  • there's no return value and you get whatever was left in the AX register

Could somebody explain why does my code below not crash and have some wired output

Doing the wrong thing isn't guaranteed to crash your program - there are no guarantees.

cnicutar
  • 178,505
  • 25
  • 365
  • 392
0

The value 16 you get back in the last output is PROBABLY the number of characters written by printf - as that's what printf returns, and in this case, nothing else happens after that in the function. But like others have said, you're asking what happens, and nobody can really say - it may not work at all, crash and burn, or give you some "random" values as return and printout - it's not defined anywhere, and if you compile the code with a different compiler, different compiler settings or on a different type of hardware, the results will change.

Each time you run the code, it will most likely give you the same result, but make some changes to the code, and unpredictable results will occur.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

To answer the question,

Could somebody explain why does my code below not crash

not all broken code actually crashes. Possibly the parameters (and the return values) of f are passed in registers instead of being pushed onto the stack, and therefore the mismatch between expected values and actual values does not translate into a stack misalignment. If you tried with more arguments, enough to require stack work, you would probably get that crash, or some possibly dangerous behaviour (a similar technique is used in some security exploits, after all).

Then to clarify usage of function pointers, I have taken the liberty of rewriting the code with a couple of comments.

#include <stdio.h>
#include <stdlib.h>

/* We want to be able to print a return value, so we make
   f return something - a long, so as to tell it from int
   - in order to be able to get something back.
*/

static long f(int x, int y){

    printf("x = %d \n",  x );
    printf("y = %d \n",  y );
    return x + y;
}

/* We want the signature of a function returning long, and taking
   two int's, since this is what f() is.
*/
typedef long (*FUNCPTR)(int, int);
typedef long (FUNC)(int, int);

int main(void)
{
    /* We want a pointer to f - it works either way */
    FUNCPTR addr   = f;
    FUNC    *addr2 = f;

    /* addr points to a function taking two ints, so we must pass it
       two ints, and format return as long decimal */

    printf("%ld\n",  addr(5, 7));

    /* addr2 is the same */

    printf("%ld\n",  addr2(5, 7));

    return 0;
}

Expected output:

$ gcc -W -Wall -o test test.c

$ ./test
x = 5
y = 7
12
x = 5
y = 7
12
LSerni
  • 55,617
  • 10
  • 65
  • 107