我试图理解什么是c中函数的指针。
我想要一些调用函数指针的详细过程,因此,我可以更好地理解指向函数的指针。
有人可以解释为什么我的代码下面没有崩溃并且有一些有线输出?
为了缩小范围,我正在寻找类似javap
的东西,它可以解释jdk
如何编译
我的代码和jvm
运行我的代码
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
答案 0 :(得分:4)
答案是未定义的行为。您正在使用两个不兼容的函数指针类型,并使用一个来调用另一个。 (更不用说将指针存储在整数等中等)。因此,您的程序会调用未定义的行为,因此,任何事情都可能发生。你得到的值很可能只是乱搞堆栈和/或CPU寄存器的随机废话。
答案 1 :(得分:3)
您在整个地方造成了未定义的行为:
试图理解这一点是不合理的,但是因为你使用的是x86:
x
在您传递的1
y
不是这样,它会得到一个随机值,可能是堆栈上剩余的一些有人可以解释为什么我的代码下面没有崩溃并且有一些 有线输出
做错事并不能保证你的程序崩溃 - 没有保证。
答案 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