关于C函数(名)的本质
我像问一问c函数(或者函数名)的本质是什么?
函数名是一个具体的存储着的变量么?
若不是,为何有:
假设f6是一个普通的函数
而
f6();
(&f6)();
(*f6)();
(********f6)();
都是正确的呢?
[解决办法]
对,函数名就是一个地址----该函数名所代表的函数的入口地址。这一点与数组名相同(数组名就是数组的首地址)。
1、(&f6)(); //对f6函数名所代表的地址取址-----取出来的地址还是它自己
2、(*f6)(); //将f6函数名所代表的地址转换为一个函数指针,该指针指向函数f6的入口地址------结果还是f6自己,也就是说此时的指针指将自己。
分析:一般的指针函数是这么用的
(*p)(); //定义一个指针变量p,该指针的类型是(*)()
f6();
p=f6; //为指针变量付址----f6函数的入口地址
而此时(*f6)();可以这样来理解: 1、将f6()函数的入口地址强制转型为一个函数指针;
譬如:假设f6代表的地址为0xffeedd88
(*)()(0xffeedd88) //将该地址强制转换为(*)()指针。
2、为该指针付值,所付的值就是它自己的地址值。
*(0xffeedd88)=f6;
当然,有些编译器里面可能不不支持这样模拟,但是原理基本上即使这样。
最后的结果就是指向函数自己的函数指针---函数名为f6。
3、(********f6)(); // 任意个*都可以
有了上面的(2)的解释,这个问题就很好解释了----对指向自己的指针取值,不论是取该指针本身的地址值还是指针所指向的值,结果都是一样,因为指针本身就是指向自己的。对数组名也一样。
-----------------以上为自己的理解,估计大体上应该正确。
[解决办法]
首先
f6 是一个符号
f6();
(&f6)();
(*f6)();
(********f6)();
这一堆的解释权归编译器所有
编译器爱解释成什么都行
按照c的解释规则
int f6;
f6 就解释为有符号整数
而
f6();
编译以前f6是两个字符
编译以后连接以前,这个f6是汇编码的一个标号_f6
(&f6)();
(*f6)();
(********f6)();
都会被转换成标号_f6
连接以后,这个标号_f6被替换成一个数字
这个数字就是函数f6的地址 这个地址对应的语句为 55 pushl %ebp
编译器根据什么把(&f6)(); (*f6)(); (********f6)(); 都转换成_f6哪(个人见解)
&f6 这个好理解 -- 我要地址的地址 结果还是它本身
*f6 编译器不知道你想干什么哦... 你是想取以f6为地址的数据区的内容吗?
那你到底要取多大的内容哪? *((char*)f6) ? *((int*)f6) ? ....
你想把代码段的内容取出来?那你要记得用cs寄存器去取挖.
既然你表达的含糊不清 *f6 也作为_f6处理吧...
这貌似是编译器的"宽容"呵呵.
[解决办法]
函数名就是一个地址----该函数名所代表的函数的入口地址。这一点与数组名相同(数组名就是数组的首地址)。
1、(&f6)(); //对f6函数名所代表的地址取址-----取出来的地址还是它自己
2、(*f6)(); //将f6函数名所代表的地址转换为一个函数指针,该指针指向函数f6的入口地址------结果还是f6自己,也就是说此时的指针指将自己。
分析:一般的指针函数是这么用的
(*p)(); //定义一个指针变量p,该指针的类型是(*)()
f6();
p=f6; //为指针变量付址----f6函数的入口地址
而此时(*f6)();可以这样来理解: 1、将f6()函数的入口地址强制转型为一个函数指针;
譬如:假设f6代表的地址为0xffeedd88
(*)()(0xffeedd88) //将该地址强制转换为(*)()指针。
2、为该指针付值,所付的值就是它自己的地址值。
*(0xffeedd88)=f6;
当然,有些编译器里面可能不不支持这样模拟,但是原理基本上即使这样。
最后的结果就是指向函数自己的函数指针---函数名为f6。
3、(********f6)(); // 任意个*都可以
有了上面的(2)的解释,这个问题就很好解释了----对指向自己的指针取值,不论是取该指针本身的地址值还是指针所指向的值,结果都是一样,因为指针本身就是指向自己的。对数组名也一样。
[解决办法]
*(0xffeedd88)=f6; //不是很矛盾吗,函数首地址存了函数的地址
[解决办法]
标准答案 (自卖自夸一下,hehe):
在标准c文档(WG14 N1124)里这样描述
A function designator is an expression that has function type. Except when it is the
operand of the sizeof operator or the unary & operator, a function designator with
type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to
function returning type’’.
也就是说函数类型表达式(如*pf)会被自动转化成函数指针. 这样你加多少个*都没有关系.
另外对一个函数指针pf, (*pf)() 和 pf() 都已成为合法的用法 (k&R 不支持 pf())。
C99 的文档里也提到这一点:
Pointers to functions may be used either as (*pf)() or as pf(). The latter construct, not
sanctioned in K&R, appears in some present versions of C, is unambiguous, invalidates no old
code, and can be an important shorthand. The shorthand is useful for packages that present only
one external name, which designates a structure full of pointers to objects and functions: member
functions can be called as graphics.open(file) instead of
(*graphics.open)(file).
说的是这样子可以方便调用结构里的函数。
[解决办法]
看一个程序:
int main()
{
int f();
int (*ff)(),i=0;
ff=f;
cout<<ff<<"\n"<<*ff<<"\n"<<**ff<<"\n"<<&ff<<"\n"<<&i<<"\n"<<endl;
f();
ff();
return 0;
}
int f()
{
cout<<"run"<<endl;
return 0;
}
运行结果是:
0x00401014
0x00401014
0x00401014
0x0012FF7C
0x0012FF78
run
run
Press any key to continue
分析可得:
1\函数名是个指向函数的地址的指针
2\函数的地址的值依然是函数的地址,如果再做个试验,可以发现一般的一级指针不具备函数指针的*运算后依然是指针的特性.这个应该就是f=*f=**f=...的缘故吧.
3\函数名变量是存放在数据区的
4\在表达式中,函数名后面的括号应该是指明该处要调用函数变量所指向的函数.
另外的测试表明:对一个一般一级指针j,*j和&j都没错,但是&&j和**j就会报错;
对于一级函数指针f,&&f报错,而**f不报错.
以上测试使用的是vc++.
本人菜鸟,有不对的地方希望大家指正,谢谢.