首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

有关函数,函数指针的有关问题。30分!还可以加分

2012-02-11 
有关函数,函数指针的问题。30分!还可以加分。#include stdio.h#include stdlib.htypedef void (*FUN)()

有关函数,函数指针的问题。30分!还可以加分。
#include <stdio.h>
#include <stdlib.h>
typedef void (*FUN)();

void Myfunction()
{
static int num(0);
printf("we have come to this function!%d\n",num++);
}
int main()
{
//////////////////////////////////////////////////////////////////////////
//为什么上面两种都可以呢?
FUN fPtr1 = Myfunction;//Myfunction的值写入。
fPtr1();
(*fPtr1)();

FUN fPtr2 = &Myfunction;//Myfunction的地址写入。
fPtr2();
(*fPtr2)();
//////////////////////////////////////////////////////////////////////////
//为什么第二种就不行了呢?
FUN fPtr4;
int *p = (int*)&Myfunction;
int *pMf = (int*)&p;
int *f = (int*)&fPtr4;
*f = *pMf;//将Myfunction的地址写入到fPtr4中。
fPtr4();//调用成功
(*fPtr4)();//调用成功

FUN fPtr3;
int* nPtr = (int*)&Myfunction;
int* nPtrFptr3 = (int*)&fPtr3;
*nPtrFptr3 = *nPtr;//将Myfunction的值写入到fPtr3中
(*fPtr3)();//调用失败
fPtr3();//调用失败

//////////////////////////////////////////////////////////////////////////
//last question:函数的调用过程到底是什么样的呢?函数地址扮演着什么角色呢?
//Myfunction这个值是什么呢?有类型吗?
//希望能够得到逐一的解答。
return EXIT_SUCCESS;
}
编译器vs2005.
可以另外加分。

[解决办法]
FUN fPtr3; 
int* nPtr = (int*)&Myfunction; 
int* nPtrFptr3 = (int*)&fPtr3; 
*nPtrFptr3 = *nPtr;//将Myfunction的值写入到fPtr3中 
(*fPtr3)();//调用失败 
fPtr3();//调用失败 
=======================================
这两句提出来:
int* nPtr = (int*)&Myfunction;//假设函数的地址是:0x00401005
*nPtrFptr3 = *nPtr;//这句的意思是到0x00401005的地方取个整数到*nPtrFptr3中,这已经不是函数的地址了.

*nPtrFptr3 = (int)nPtr;//改为这样就对了.


函数的地址就是一个值,当然,在编译时是有类型的值.无论你怎么变,不能把它本身的值变了.

[解决办法]
首先,对于:

//为什么上面两种都可以呢? 
FUN fPtr1 = Myfunction;//Myfunction的值写入。 
fPtr1(); 
(*fPtr1)(); 

FUN fPtr2 = &Myfunction;//Myfunction的地址写入。 
fPtr2(); 
(*fPtr2)(); 

是因为,通常情况下,一个对象名作为初始值时代表值传递,而对象名加&解析符代表地址传递,但对于函数名而言是一个例外,当以函数名为相对应类型的函数指针赋值(或作为参数传递)的时候,编译器把"Myfunction"与"&Myfunction"视为等同语句 -都是获得函数地址!(见《C++ Common Knowledge》条款14-函数指针page37》)

其次对于你的下述代码,请允许我为你注释:

FUN fPtr4 = NULL; 
int *p = (int*)&Myfunction;//函数地址赋值与整型指针p,可以认为p就是函数指针(当然已被强制转型!); 
int *pMf = (int*)&p;//令pMf指针指向p;(这是一个所谓的"指针的指针"!) 
int *f = (int*)&fPtr4;//令f指向函数指针变量fPtr4; (也是一个所谓的"指针的指针"!)
*f = *pMf;//pMf对f解引用赋值;

//如上pMf与f解引用赋值的结果,使其等同于语句: fPtr4 = p;//fPtr4获取到正确的函数指针!

fPtr4();//调用成功 合法的调用...... 
(*fPtr4)();//调用成功

然而后面的情况不佳,请允许我继续为你注释你的程序:

FUN fPtr3 = NULL; 
int* nPtr = (int*)&Myfunction;//取函数地址在nPtr,等同于nPtr是函数指针! 
int* nPtrFptr3 = (int*)&fPtr3; //令nPtrFptr3指向fPtr3(也即指针的指针);

*nPtrFptr3 = *nPtr;//!!!!

/*
如上的双解引用,等同于fPtr3 = *nPtr;
要注意的是:fPtr3得到的不是函数指针nPtr,而是该指针nPtr的非法解引用-指向执行指令代码的地址!
*/

(*fPtr3)();//调用失败,非法的调用! 
fPtr3();//调用失败

关于最后一个问题:函数的调用过程到底是什么样的呢?函数地址扮演着什么角色呢?

答:基本上就编译器底层而言,所有的函数调用(包括类成员函数),除内联函数外,都是以函数指针调用到函数代码实体!

例如一个非成员函数void show(void)是这样调用:

(*_VoidShowVoid)();//调用!

一个名为_fish对象(类实例)的成员函数调用_fish.memberfun()是这样:

(*_voidFishMemberfuncvoid)(&_fish);//其中_fish即是该对象的this指针!

上述函数指针名视不同的编译器的mangling策略不同而大同小异!可见函数指针就是调用函数的handle!

对于"Myfunction"这个函数名,我可以认为它就是函数指针,而函数指针肯定是有类型的,因为一个没有类型的东西,编译器将无所适,不确定其sizeof,这根本就无法寻址。而函数指针的类型就是函数的原型!例如上述Fun,就是一个所有类似:

void Myfunction(void);//无返回值、无参数的函数; 

函数原型的typedef!

还有一个问题是,上述程序用了大量的C风格的强制类型转换为int型指针,但在最后又都隐式的转换成了Fun型函数指针,这在本程序而言不是一个问题,但这样的代码不够健壮,而且平台移植性也非常的糟!




[解决办法]
学习
[解决办法]
在debug模式下,你可以看到 两个函数指针的值不是一样的.
FUN fPtr1 = Myfunction;//Myfunction的值写入。
fPtr1();
(*fPtr1)();

FUN fPtr2 = &Myfunction;//Myfunction的地址写入。
fPtr2();
(*fPtr2)(); 
你可以使用relase试试,不过既然强制转换的代码在debug下无法运行,那就说明你的强制转换不对.
不应该这样使用.
[解决办法]
对于函数名语言是有特殊规定的,&MyFunction和MyFunction都表示他首址

注意:这个特殊规定只对函数名有效,当你使用int*做中转时,&算子会使得指针增加一级,上面的这个规则就无效了

所以没有啥为什么,就是乌龟的屁股--规(龟)定(腚)
[解决办法]
致huangyimin朋友:

你真的认为判断一个标识符或其它什么东西是不是类型,是以能不能进行sizeof运算作为依据的吗?

你说:"函数原型的sizeof是多少呢?好像sizeof(Myfunction)不行哈,编译不过。",下列代码可以告诉你:

typedef void (*FUN)();

int main()
{
cout << "这个函数指针类型的sizeof运算是: " << sizeof(FUN) << endl;

_PAUSE;
return 0;
}

执行上述程序,其输出算是对你的回答!(它说明在我的32位windows平台上函数指针是4byte)

其次请再看如下程序:

typedef void (*FUN)();
typedef int (*FUNC)(const double& _d);//声明了一个新类型的别名!

void Myfunction()
{
static int num(0);
printf("we have come to this function!%d\n",num++);
}

int main()
{
//////////////////////////////////////////////////////////////////////////
FUN fPtr1 = Myfunction;//Myfunction的值写入。
fPtr1();

/*
如下语句生成错误!
类似BC6.0:"E2034 Cannot convert 'void (*)()' to 'int (*)(const double &)'"
类似VC编译器:
Error C2440:
“conversion”: 无法从“type1”转换为“type2”编译器无法从“type1”转换为“type2”。

*/
FUNC fPtr2 = Myfunction;

_PAUSE;
return 0;
}

上述示例说明,编译器是依靠类型糸统,在识别从Myfunction到fPtr2的赋值转换许可!关于函数指针及函数指针的类型,众多的C++书籍均有祥解(比如《C++ Primer》第7.9.1章节),在此不再论述。


热点排行