首先看小段代码:
#include <stdio.h>
int func()
{
printf("in func\n");
}
int (*pfunc)();
int main()
{
printf("func = %x\n",func);
pfunc = func;
printf("*pfunc = %x\n",*pfunc);
printf("pfunc = %x\n",pfunc);
getchar();
}
打印结果:
func = 4012d0
*pfunc = 4012d0
pfunc = 4012d0
不理解的是*pfunc和pfunc值为什么是一样的呢?
请高手帮帮忙!
另外关于指针和数组还有一点不明:
对于一个数组
int array[10];
为什么 array 与 &array 的值是一样的呢?
期待高手的解惑!
现回答你的函数指针疑问。
我的思路是通过反汇编来剖析编译器在背后为我们做了些什么。
unsigned long pfuncAddr = (unsigned long)&pfunc;
01386E2E mov dword ptr [pfuncAddr],offset pfunc (139051Ch)
printf("pfunc addr = %x\n", pfuncAddr);
01386E35 mov esi,esp
01386E37 mov eax,dword ptr [pfuncAddr]
01386E3A push eax
01386E3B push offset string "pfunc addr = %x\n" (138DAACh)
01386E40 call dword ptr [__imp__printf (13914D8h)]
01386E46 add esp,8
01386E49 cmp esi,esp
01386E4B call @ILT+1025(__RTC_CheckEsp) (1381406h)
pfunc = func;
01386E50 mov dword ptr [pfunc (139051Ch)],offset func (1381483h)
printf("*pfunc = %x\n", *pfunc);
01386E5A mov esi,esp
01386E5C mov eax,dword ptr [pfunc (139051Ch)]
01386E61 push eax
01386E62 push offset string "*pfunc = %x\n" (138DAC4h)
01386E67 call dword ptr [__imp__printf (13914D8h)]
01386E6D add esp,8
01386E70 cmp esi,esp
01386E72 call @ILT+1025(__RTC_CheckEsp) (1381406h)
printf("pfunc = %x\n", pfunc);
01386E77 mov esi,esp
01386E79 mov eax,dword ptr [pfunc (139051Ch)]
01386E7E push eax
01386E7F push offset string "pfunc = %x\n" (138DA14h)
01386E84 call dword ptr [__imp__printf (13914D8h)]
01386E8A add esp,8
01386E8D cmp esi,esp
01386E8F call @ILT+1025(__RTC_CheckEsp) (1381406h)
以下代码是为了获取pFunc函数指针变量地址,打印的结果是139051Ch,从这个事实可以判断,pfunc是一个全局变量。
unsigned long pfuncAddr = (unsigned long)&pfunc;
我们在回到反汇编后的代码:
01386E5C mov eax,dword ptr [pfunc (139051Ch)]
01386E79 mov eax,dword ptr [pfunc (139051Ch)]
这里有两个细节需要注意:
1, 代码pfunc 和 *pfunc反汇编后是一样的。
从这点我们可以知道,编译器在编译期就把pfunc 等同于 *pfunc。
2, dword ptr [pfunc (139051Ch)] 都是取地址139051Ch内容,而这个值就是我们前面取到的值。
同样的方法也可以解决你数组名的疑问。
先回答指针与数组名称的问题,编译器对于指针和数组名称的处理是不同:指针是一个变量,因此编译器会给其申请地址空间,而编译器把数组名看成是一个符号,不会给其分配地址空间,它记录的仅仅是array[0]的地址而已。因此,array和&array的值是一样的,都是array[0]的地址。
关于数组名称和指针变量的区别,可以看下链接中的专题探讨
http://www.cnblogs.com/welkinwalker/archive/2011/09/07/2170165.html
然后再来说,函数指针的问题:
声明了函数指针后,即iint (*pfunc)(); 编译器并未给其分配空间,而是将其当作符号来处理,记录下函数堆栈的首地址,你可以在对其赋值之前,打印*pfunc和pfunc的值,你可以看到输出都为0,因为没有将任何函数堆栈地址给它赋值;实际上函数名是一种隐式指针,而你在打印pfunc的值时,编译器会将其按照*pfunc对待并打印。因此*pfunc和pfunc的值都一样;
(1)、func = 4012d0 这个好理解了吧,就是func入口的地址
(2)、*pfunc = func = 4012d0 这个关系你懂的了。*pfunc的意义是pfunc所指向的函数入口地址为4012d0
(3)、pfunc = 4012d0 这个是因为pfunc是一个指针变量,也相当一个无符号的整型变量,里面存放着一个函数的入口地址。这个函数的地址就是 4012d0,这一点上面已经验证了。
(4)、你想要的,且有所不同的应该是这个东西 &pfunc 。变量pfunc的地址。
(5)、array 与 &array 。在编译器看来array是一个数组名,也即是一段内存的起始地址。而&array是显示地获得array数组的起始地址,和&array[0]是一样的。
都被你们回答了。。。。