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]正确运行。
我的分析就是这样了,贴出来,是想让高手们看看我哪里是不是出现问题,因为我感觉这本书写得很专业并且很认真,会不会是编译器的问题?
hawkerxh 于 2011-08-06 23:44:55发表:
为下载捞分,顶楼主。
wq413732076 于 2011-08-05 19:03:17发表:
感谢楼主分享 我要学linux
jasonlv 于 2011-05-18 13:19:52发表:
学习
zhang0tie0min0 于 2011-04-06 15:59:33发表:
~~~~~~~~~~~~~~~~~~
naruto01 于 2010-05-27 20:11:12发表:
你编译的是一开始我给出的代码吗?
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
naruto01 于 2010-05-26 21:58:03发表:
8# prinse
Ubuntu带的gcc编译
super0208 于 2010-05-26 19:57:44发表:
学习下....
prinse 于 2010-05-26 17:47:06发表:
LZ 贴的代码没有任何问题啊……,不知道楼主是不是用 C++ 编译器编译?C++ 是强类型检查的,这份代码是用 C 写的,存在类型问题,所以楼主要是用 C++ 编译器编译,有那样的出错误信息一点都不奇怪……
niuda_1 于 2010-05-26 11:12:24发表:
纯粹交任务
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]
child7 于 2010-05-25 09:26:02发表:
楼主强大,随便学习
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运行起来就没有问题了。
我估计是作者笔误吧。
Relief 于 2010-05-25 08:32:19发表:
楼主很强啊
shenhao0129 于 2010-05-25 00:06:14发表:
基本上如果不是对应寄存器的话,是不能取常量的地址的,这个属于系统保护那部分,否则系统还不直接崩溃掉了啊?但是在嵌入式里面,寄存器或者I/o地址确实个例外