LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 3107|回复: 12

使用函数指针pFun(x),(*pFun)(x)结果一样,为什么?

[复制链接]
发表于 2008-3-10 11:19:13 | 显示全部楼层 |阅读模式
  1. #include <stdio.h>
  2. typedef char (*PTRFUN)(int);//指向函数的指针
  3. char glFun(int a)
  4. {
  5.         putchar( a);
  6.         putchar('\n');
  7.         return a;
  8. }
  9. int main()
  10. {
  11.     PTRFUN pFun;
  12.         pFun = glFun;
  13.     pFun('A');
  14.     (*pFun)('A');
  15.         return 0;
  16. }
复制代码

从gdb看去,pFun和*pFun的值确实相同,但*pFun的类型更加安全。
(gdb) p pFun
$4 = 0x804836c <glFun>
(gdb) p *pFun
$5 = {char (int)} 0x804836c <glFun>
发表于 2008-3-10 12:25:23 | 显示全部楼层
确实, 过去还真没考虑过函数指针的类型安全问题. 感谢 realtang 兄提醒
回复 支持 反对

使用道具 举报

发表于 2008-3-10 13:13:18 | 显示全部楼层
受教。。。。
回复 支持 反对

使用道具 举报

发表于 2008-3-10 15:19:16 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2008-3-10 15:22:30 | 显示全部楼层
参见以下网址,对这个问题讲得很详细

http://blog.programfan.com/article.asp?id=6030
回复 支持 反对

使用道具 举报

发表于 2008-3-11 09:26:56 | 显示全部楼层
很多年前提过这个问题:
http://www.linuxsir.cn/bbs/showthread.php?t=55310
这里有个function pointer tutorial:
http://www.newty.de/fpt/fpt.html#assign

其实,楼上给出blog中的结论并不准确:
1. 其实,MyFun的函数名与FunP函数指针都是一样的,即都是函数指针。MyFun函数名是一个函数指针常量,而FunP是一个函数数指针变量,这是它们的关系。
2. 但函数名调用如果都得如(*MyFun)(10);这样,那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许MyFun(10);这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。
3. 为统一起见,FunP函数指针变量也可以FunP(10)的形式来调用。
4. 赋值时,即可FunP=&MyFun形式,也可FunP=MyFun。
上述代码的写法,随便你爱怎么着

函数名不是指针,只是在表达式中被evaluated成函数的入口地址而已。
这一点跟数组名类似。
&myFun的方式更加的portable
回复 支持 反对

使用道具 举报

发表于 2008-3-11 09:38:35 | 显示全部楼层
这样都行的:
#include <stdio.h>

void aa(void) {
        puts("test");
        }
int main(void) {
        aa();
        (*aa)();
        return(0);

}
[root@td17 tmp]# ./p
test
test


回复 支持 反对

使用道具 举报

发表于 2008-3-11 12:19:30 | 显示全部楼层
这涉及到 C 的语义。由于现在的计算机教育往往从 C 开始,就忽视了对 C 的语义的理解而通过观察已有程序的例子从“表向”上去理解 C 如何工作。在大多数情况下这是可行的,但涉及到像这里所遇到的细节时就不得不回到语义上去。我下面的讨论以 C99 标准为背景,这份标准可以在 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf 下载到。

Post by realtang;1824791

  1. #include <stdio.h>

  2. typedef char (*PTRFUN)(int);//指向函数的指针

  3. char glFun(int a)
  4. {
  5.         putchar( a);
  6.         putchar('\n');
  7.         return a;
  8. }

  9. int main()
  10. {
  11.     PTRFUN pFun;
  12.         pFun = glFun;
  13.     pFun('A');
  14.     (*pFun)('A');
  15.         return 0;
  16. }
复制代码


从gdb看去,pFun和*pFun的值确实相同,但*pFun的类型更加安全。
(gdb) p pFun
$4 = 0x804836c <glFun>
(gdb) p *pFun
$5 = {char (int)} 0x804836c <glFun>


标准的 6.3.2.1 定义了 function designator 的概念:

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’’.


上面的例子中 g1Fun 就是一个 function designator。

6.5.2 节定义了函数调用的限制和语义。6.5.2.1 节中说:

The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.


并且在脚注 77 中,标准明确地指出“大多数情况下这是转换一个是 function designator 的标识符得到的结果”。回到 realtang 的例子,

pFun('A');


是不需转义的写法,因为 pFun 本身就是一个指向函数的指针的类型。后一种写法,以及下面 dajun 的写法:

Post by dajun;1825152
这样都行的:
#include <stdio.h>

void aa(void) {
        puts("test");
        }
int main(void) {
        aa();
        (*aa)();
        return(0);

}
[root@td17 tmp]# ./p
test
test




其语义可以在 6.5.3.2 节找到:

The unary * operator denotes indirection. If the operand points to a function, the result is a function designator;


即,(*pointer_to_func) 先被转换为 function designator,再转换成 pointer to function。当然,这些都是在编译时完成的。我也给出一个写法:


  1. #include <stdio.h>

  2. typedef char FUN (int);

  3. char
  4. g1Fun (int a)
  5. {
  6.   putchar (a);
  7.   putchar ('\n');
  8.   return a;
  9. }


  10. int
  11. main (int argc, char *argv[])
  12. {
  13.   FUN *pFun = g1Fun;

  14.   pFun ('A');

  15.   return 0;
  16. }
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-3-11 12:49:45 | 显示全部楼层
根据herberteuler兄的分析,看来还是pFun('A')少走弯路了,而且也是类型安全的。这么来看,gdb给出的结果有问题。
回复 支持 反对

使用道具 举报

发表于 2008-3-11 13:22:35 | 显示全部楼层
Post by realtang;1825230
根据herberteuler兄的分析,看来还是pFun('A')少走弯路了,而且也是类型安全的。这么来看,gdb给出的结果有问题。
应该没有问题吧,
(gdb) p pFun
$4 = 0x804836c <glFun>

这是一个指针,它指向的内容是函数 glFun,
(gdb) p *pFun
$5 = {char (int)} 0x804836c <glFun>

*pFun 的类型是函数,它接受一个 int 类型的参数,返回一个 char 类型的结果。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表