回 帖 发 新 帖 刷新版面

主题:[讨论]《Linux C编程一站式学习》的一个错误,欢迎讨论

第 24 章 函数接口 5. 回调函数 例 24.7. 回调函数
[code=c]
/* 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=c]
/* para_callback.c */
#include "para_callback.h"

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

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

void count_numbers(void *num)
{
        int i;
[color=Green]        for(i=1; i<=(int)num; i++)[/color]
                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=c]
main.c: In function 'count_numbers':
main.c:12: warning: cast from pointer to integer of different size
[/code]
大致一看,根据参数类型,传入的是void *指针,调用时直接用num来取值,没问题啊。(我以前没注意过这个问题,根据例子猜想的。)
然后我试验了这个想法:
源代码:
[code=c]
#include <stdio.h>

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

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

void printnum(int *num)
{
[color=Green]        printf("%d\n",*num);[/color]
}

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

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

回复列表 (共7个回复)

沙发

问题显然出在你的编译环境里void*的长度跟int的长度是否一致。如果你的编译环境里int跟void*不一样长,就会产生这个warning了

板凳

意思是说如果长度一致就可以编译通过了?
void *不是通用指针吗?很明显和int不是一个概念。怎么能够互相转换呢?

3 楼

void * 默认C里的指针长度是4个字节,在VC里int的长度也是4个字节!

4 楼

[quote]void * 默认C里的指针长度是4个字节,在VC里int的长度也是4个字节![/quote]
哦~我表达错了。
我的意思是说指针是指针,int是int,即使是长度一致,怎么能够强制转换呢?(注意这里是pointer转换int,而不是pointer所指的地址的值,即*pointer)

这个讨论我认为对这个问题没有必要。我想讨论的就是一个在函数中使用参数方式的问题,在例子中我已经指出。

5 楼

强制转换,不就是想干啥干啥嘛。
函数参数使用要与声明一致

6 楼

你把void count_numbers(void *num)函数里的i<=*((int *)num)改成i<=(int)(*num)试试

7 楼

刚才回的有点问题,你把4强制转换成地址变量,而在函数count_numbers又将4转换成int型变量,这在windows下也与可以实现,但在Linux下是不可能的,这样程序的稳定性也将大大降低。建议还是好好学一下基础,不要把简单问题复杂化。

我来回复

您尚未登录,请登录后再回复。点此登录或注册