免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: plp626
打印 上一主题 下一主题

[C] int (fun)(char *) 的问题 [复制链接]

论坛徽章:
0
31 [报告]
发表于 2012-09-27 18:25 |只看该作者
本帖最后由 plp626 于 2012-09-27 18:26 编辑

大伙谁能否分析下10楼代码的段错误缘由?
不准用调试器。。

    (*pfun)("aaaa");
  4012d9:        8b 45 fc                     mov    0xfffffffc(%ebp),%eax
  4012dc:        c7 04 24 a8 12 40 00         movl   $0x4012a8,(%esp,1)
  4012e3:        8b 00                        mov    (%eax),%eax
  4012e5:        ff d0                        call   *%eax

    (**pfun)("aaaa");
  4012d9:        8b 45 fc                     mov    0xfffffffc(%ebp),%eax
  4012dc:        c7 04 24 a8 12 40 00         movl   $0x4012a8,(%esp,1)
  4012e3:        8b 00                        mov    (%eax),%eax
  4012e5:        ff d0                        call   *%eax

    ((int(*)(char *))pfun)("aaaa");
  4012d9:        c7 04 24 a8 12 40 00         movl   $0x4012a8,(%esp,1)
  4012e0:        8b 45 fc                     mov    0xfffffffc(%ebp),%eax
  4012e3:        ff d0                        call   *%eax

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
32 [报告]
发表于 2012-09-27 18:40 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
33 [报告]
发表于 2012-09-27 21:32 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
34 [报告]
发表于 2012-09-27 21:45 |只看该作者
  1. #include <stdio.h>
  2. int foo(char *s)
  3. {
  4.     puts(s);
  5.     return 0;
  6. }

  7. int   main()
  8. {
  9.     int fun(char *); // 声明了一个函数 [color=Red]没啥好说的[/color]
  10.     int (fun)(char *); // ?????[color=Red]这个括号可以忽略,和上面那句一样。函数可以多次声明,只要相互不冲突。[/color]

  11.     int (*pfun)(char *); // 定义了一个函数指针 [color=Red]没啥好说的[/color]

  12.     pfun = foo;   [color=Red]foo是一个函数,但是C编译器的牛逼之处就在于在需要函数指针的时候,会自动帮你把函数转化为其指针:pfun = &foo。[/color]
  13.     (*pfun)("aaaa"); // 正确  [color=Red]这是最标准的写法[/color]
  14.     pfun("aaaa");   // 正确 [color=Red]pfun是函数指针,所以C编译器自动理解为:(*pfun)("aaaa"); [/color]

  15.     pfun = &foo; [color=Red]这里开始和上面没区别了,因为pfun = &foo和pfun = foo对编译器来说是一样的。[/color]
  16.     (*pfun)("aaaa");  // 正确
  17.     pfun("aaaa");     // 正确
  18.     return   0;
  19. }
复制代码

论坛徽章:
3
寅虎
日期:2013-11-27 07:53:29申猴
日期:2014-09-12 09:24:152015年迎新春徽章
日期:2015-03-04 09:48:31
35 [报告]
发表于 2012-09-27 22:00 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
36 [报告]
发表于 2012-09-27 22:06 |只看该作者
回复 31# plp626

贴段汇编代码还反白不许看。。。而且还是高爷爷的头像。。。以为是多高深的代码。。。
一瞅。。。  这代码。。。

  1. pfun = &foo;
  2. /*
  3. foo  : int (char*)
  4. &foo : int (*)(char*)
  5. pfun : int (**)(char*)
  6. */
复制代码
类型对不上啊。。。编译器给的警告就不管了吗。。。
虽然C的类型系统聊胜于无,但既然它都能找到机会报告了,还是看一看呗。。。


我看不懂那段汇编,at&t格式的看起来吃力。顺手改改,我不知道为什么它是对的,但总之它就是对的。

  1. #include <stdio.h>

  2. int foo(char* s)
  3. {
  4.       puts(s);
  5.       return 0;
  6. }

  7. int main(void)
  8. {
  9.       int (**pfun)(char*);
  10.       int (*f)(char*) = foo;
  11.       pfun = &f;
  12.       (*pfun)("implicit: function -> pointer to function");
  13.       return 0;
  14. }
复制代码
然后发现11楼已经有这个答案了。
然后还发现20楼把该说的都说完了。。。

sonicling 发表于 2012-09-22 09:08
回复 13# plp626

弄清楚两个问题就好了。

1. 表达式的类型是什么?
2. 有哪些隐式类型转换?


foo的类型是函数(C语言有这个类型的),不是函数指针。
只是它在一些场合下会隐式转换为函数指针类型 —— 想想数组。
比如 int (*f)(char*) = foo;
int (*g)(char*) = &foo; 与上面一样。
&foo == foo

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
37 [报告]
发表于 2012-09-28 00:40 |只看该作者
回复 31# plp626

本想写个程序,调教foo,使得它的指令的头4个字节按指针解释就是一个函数(甚至就是foo自己)的地址。

  1. _foo :
  2.   b0 b1 b2 b3 ...
复制代码
让b0-b3既是foo的指令,同时按指针解释后能得到一个函数的地址。 (*pfun)(""); 就不会出错了。

不过功力不够还欠火候,没调教成功。。。

论坛徽章:
0
38 [报告]
发表于 2012-09-28 15:06 |只看该作者
和数组名类似, 函数名当做右值使用时它就是指针了,
我说的“函数名,函数指针,函数指针的指针”不很严谨,改为“右值函数名,函数指针,函数指针的指针”
这个问题不再讨论了
---------------------------------
大家现在把注意力放在31楼吧,可以同时再看看11楼和26楼的回帖

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
39 [报告]
发表于 2012-09-28 16:22 |只看该作者
回复 31# plp626

我还是不知道反白内容是什么,我读at&t吃力于是就懒得看。

昨天我尝试在windows上调教出一个demo演示(*pfun)到底是在做什么。
但因为windows上有各种限制 —— section、函数要求对齐,地址空间不如linux(我没开3G模式) —— 没能成功。
起来发现LZ你还在纠结这问题。。。


我特地切换到ubuntu(804),写了一段代码,用gcc4.2.4调教成功了。

  1. #include <stdio.h>

  2. __attribute__ ((section ("at")))
  3. void foo(char const* s) { puts(s+12); }

  4. int main(void)
  5. {
  6.       void (**pfun)(char const*) = foo; /* 此处是&foo还是foo都一样 */
  7.       (*pfun)("0123456789abcdef"); /* 与10楼、11楼、36楼对比 */
  8.       return 0;
  9. }
复制代码
编译参数:

  1. gcc -fomit-frame-pointer -fno-align-functions -O2 -Wl,--section-start,at=04244483 self_ref.c
复制代码
运行:

  1. ./a.out
  2. cdef
复制代码
原因在这里:
objdump -d a.out
...
Disassembly of section at:

04244483 <foo>:
4244483:        83 44 24 04 0c               addl   $0xc,0x4(%esp)
4244488:        e9 67 3e e0 03               jmp    80482f4 <puts@plt>
...

就是我昨天没尝试成功的:让foo的前4个字节既是指令,又恰好是一个地址,甚至还指向foo自身。

LZ你满意了么? 可以不纠结这问题了么?



本来10楼就是一个很搓的问题。和printf("%d", 1.2)一样搓。为什么不规规矩矩的按照规范 —— C语言的规范,而不是什么什么团队的规范 —— 写代码?

作为兴趣,这样的问题也不是不可以探讨。
我还是很开放的,对研究这些问题持欢迎态度,厌恶的只是 i) 分不清实现与规范 ii) 将这些研究成功不加考虑(甚至是刻意为了炫耀)直接用在非娱乐代码里。
可这问题有毛好研究的啊? 这不是一眼就看出将foo的指令当地址解释了啊?
没看出? 好,11楼代码已经演示了
不知道为什么? 好, 20也把原因说了。
即使还不明白, 根据我的猜测, 你自己不也在31楼通过调试找出原因了么?

plp626 发表于 2012-09-28 15:06
大家现在把注意力放在31楼吧,可以同时再看看11楼和26楼的回帖


我是真不明白31楼还有啥值得留意的,值得讨论的,值得把注意力放上去的?


最后,即使你在26楼想通了, 如非必要, 不要将函数指针与数据指针(包括函数指针的指针)混用。

论坛徽章:
0
40 [报告]
发表于 2012-09-28 16:35 |只看该作者
呵呵,楼上说话很有意思
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP