红联Linux门户
Linux帮助

【已结贴】《Linux C编程一站式学习》的一个问题,欢迎讨论

发布时间:2010-05-24 22:05:05来源:红联作者:naruto01
[i=s] 本帖最后由 naruto01 于 2011-10-9 17:59 编辑 [/i]

2011.10.09更新 所出问题应该在机器架构上。

第 24 章 函数接口 5. 回调函数 例 24.7. 回调函数[code]/* para_callback.h */
#ifndef PARA_CALLBACK_H
#define PARA_CALLBACK_H

typedef void (*callback_t)(void *);
extern void repeat_three_times(callback_t, void *);

#endif[/code][code]/* para_callback.c */
#include "para_callback.h"

void repeat_three_times(callback_t f, void *para)
{
f(para);
f(para);
f(para);
}[/code][code]/* main.c */
#include
#include "para_callback.h"

void say_hello(void *str)
{
printf("Hello %s\n", (const char *)str);
}

void count_numbers(void *num)
{
int i;
for(i=1; i<=(int)num; i++)
printf("%d ", i);
putchar('\n');
}

int main(void)
{
repeat_three_times(say_hello, "Guys");
repeat_three_times(count_numbers, (void *)4);
return 0;
}[/code]编译main.c没有通过,报错如下:[code]main.c: In function 'count_numbers':
main.c:12: warning: cast from pointer to integer of different size[/code]大致一看,根据参数类型,传入的是void *指针,调用时直接用num来取值,没问题啊。(我以前没注意过这个问题,根据例子猜想的。)
然后我试验了这个想法:
源代码:[code]#include

void printnum(int *num)
{
printf("%d\n",num);
}

int main(void)
{
int i = 3;
printnum(&i);
return 0;
}[/code]编译通过,运行结果是一个随机数。
改为[code]#include

void printnum(int *num)
{
printf("%d\n",*num);
}

int main(void)
{
int i = 3;
printnum(&i);
return 0;
}[/code]正确运行。
想想传送函数的是指针,已经不是在main函数里面的变量了,所以一切都应该严格按照指针来操作。
由此更改原先的代码(main.c):[code]/* main.c */
#include
#include "para_callback.h"

void say_hello(void *str)
{
printf("Hello %s\n", (const char *)str);
}

void count_numbers(void *num)
{
int i;
for(i=1; i<=*((int *)num); i++)
printf("%d ", i);
putchar('\n');
}

int main(void)
{
repeat_three_times(say_hello, "Guys");
repeat_three_times(count_numbers, (void *)4);
return 0;
}[/code]可以顺利编译,运行出现Segmentation fault。
问题锁定在(void *)4
俺菜鸟一只,还真不晓得C语言能不能取常量的地址,网上搜索无果。那么就暂时认为不可以吧。
修改[code]int main(void)
{
int i = 4;
repeat_three_times(say_hello, "Guys");
repeat_three_times(count_numbers, (void *)&i);
return 0;
}[/code]正确运行。

我的分析就是这样了,贴出来,是想让高手们看看我哪里是不是出现问题,因为我感觉这本书写得很专业并且很认真,会不会是编译器的问题?
文章评论

共有 15 条评论

  1. hawkerxh 于 2011-08-06 23:44:55发表:

    为下载捞分,顶楼主。

  2. wq413732076 于 2011-08-05 19:03:17发表:

    感谢楼主分享 我要学linux

  3. jasonlv 于 2011-05-18 13:19:52发表:

    学习

  4. zhang0tie0min0 于 2011-04-06 15:59:33发表:

    ~~~~~~~~~~~~~~~~~~

  5. naruto01 于 2010-05-27 20:11:12发表:

    你编译的是一开始我给出的代码吗?

  6. prinse 于 2010-05-27 14:17:39发表:

    我在 Fedora 13 下用 gcc 4.4.4 编译一点问题都没有:

    gcc -O2 aa.c -o aa

    要是用 C++ 编译就来事了:

    g++ -O2 aa.c -o aa

  7. naruto01 于 2010-05-26 21:58:03发表:

    8# prinse
    Ubuntu带的gcc编译

  8. super0208 于 2010-05-26 19:57:44发表:

    学习下....

  9. prinse 于 2010-05-26 17:47:06发表:

    LZ 贴的代码没有任何问题啊……,不知道楼主是不是用 C++ 编译器编译?C++ 是强类型检查的,这份代码是用 C 写的,存在类型问题,所以楼主要是用 C++ 编译器编译,有那样的出错误信息一点都不奇怪……

  10. niuda_1 于 2010-05-26 11:12:24发表:

    纯粹交任务

  11. naruto01 于 2010-05-25 10:21:12发表:

    4# deepwhite [code]main.c: In function "main":
    main.c:21: error: lvalue required as unary '&' operand[/code]

  12. child7 于 2010-05-25 09:26:02发表:

    楼主强大,随便学习

  13. deepwhite 于 2010-05-25 08:53:21发表:

    这本书我没看过,但是这个例子里面,回调函数的原型里面指明了其所需参数为指针,但是 repeat_three_times(count_numbers, (void *)4)
    却给了一个0x00000004作为参数,该值如果作为指针的话,其指向的内容为不确定值,八 成指向了内核里面。其输出结果为随机值很正常。
    如果改成
    repeat_three_times(count_numbers, (void *)&4),那么第二个参数就变成了4的地址指 针,count_numbers运行起来就没有问题了。

    我估计是作者笔误吧。

  14. Relief 于 2010-05-25 08:32:19发表:

    楼主很强啊

  15. shenhao0129 于 2010-05-25 00:06:14发表:

    基本上如果不是对应寄存器的话,是不能取常量的地址的,这个属于系统保护那部分,否则系统还不直接崩溃掉了啊?但是在嵌入式里面,寄存器或者I/o地址确实个例外