理解调用指向函数的指针

时间:2013-02-03 11:04:53

标签: c function-pointers

我试图理解什么是c中函数的指针。

我想要一些调用函数指针的详细过程,因此,我可以更好地理解指向函数的指针。

有人可以解释为什么我的代码下面没有崩溃并且有一些有线输出? 为了缩小范围,我正在寻找类似javap的东西,它可以解释jdk如何编译 我的代码和jvm运行我的代码

  1. 无效回报与14,15或16号的关系是什么。 (void函数返回)
  2. 我的第二个参数是否有任何安全问题,或者它与非初始值相同?
  3. 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;
    }
    
    在使用i686-apple-darwin11-llvm-gcc-4.2

    编译的mac os上输出

    x = 1 
    y = 1479046720 
    16 
    

4 个答案:

答案 0 :(得分:4)

答案是未定义的行为。您正在使用两个不兼容的函数指针类型,并使用一个来调用另一个。 (更不用说将指针存储在整数等中等)。因此,您的程序会调用未定义的行为,因此,任何事情都可能发生。你得到的值很可能只是乱搞堆栈和/或CPU寄存器的随机废话。

答案 1 :(得分:3)

您在整个地方造成了未定义的行为:

  • 您将函数指针存储在一个整数中,但不保证能够正常工作
  • 您正在将所述整数转换为具有不同返回类型的不同类型的函数指针(较少的参数)
  • 您正在使用比预期更少的参数调用该函数
  • 从函数返回void
  • 获取返回值

试图理解这一点是不合理的,但是因为你使用的是x86:

  • x在您传递的1
  • 的函数中正确填充
  • y不是这样,它会得到一个随机值,可能是堆栈上剩余的一些
  • 没有返回值,你可以得到AX寄存器中的任何内容
  

有人可以解释为什么我的代码下面没有崩溃并且有一些   有线输出

做错事并不能保证你的程序崩溃 - 没有保证。

答案 2 :(得分:0)

你在最后一个输出中得到的值16可能是printf写的字符数 - 就像printf返回的那样,在这种情况下,在函数之后没有其他事情发生。但就像其他人所说的那样,你问的是会发生什么,没有人能说出来 - 它可能根本不起作用,崩溃和烧毁,或者给你一些“随机”值作为返回和打印输出 - 它没有在任何地方定义,如果如果使用不同的编译器,不同的编译器设置或不同类型的硬件编译代码,结果将会改变。

每次运行代码时,它很可能会给您相同的结果,但会对代码进行一些更改,并且会发生不可预测的结果。

答案 3 :(得分:0)

要回答这个问题,

  

有人可以解释为什么我的代码不会崩溃

并非所有损坏的代码都会崩溃。可能f的参数(和返回值)在寄存器中传递而不是被压入堆栈,因此预期值和实际值之间的不匹配不会转换为堆栈未对准。如果您尝试使用更多参数,足以要求堆栈工作,那么您可能会遇到崩溃或一些可能危险的行为(毕竟,在某些安全漏洞中使用了类似的技术)。

然后为了澄清函数指针的用法,我冒昧地用几条注释重写代码。

#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;
}

预期产出:

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

$ ./test
x = 5
y = 7
12
x = 5
y = 7
12