Programming 版 (精华区)

发信人: SwordLea (飞刀李), 信区: Programming
标  题: [合集] 由bsearch引起的讨论
发信站: 哈工大紫丁香 (2003年12月07日08:59:03 星期天), 站内信件


────────────────────────────────────────
 xceman (辉->光阴匆匆似流水)          于 2003年12月03日16:18:31 星期三 说道:

一般比较函数的返回至应该设置成int类型,
我为了节省空间设置成了char类型(8位整形数),
在函数内部比较的时候一切正常,但是作为函数指针放到bsearch中的时候,
在bsearch中就出错,不能够将返回至正确的复制,出错的代码是这一段:
if (!(result = (*compare)(key,mid)))
      return(mid);
这是c库函数bsearch源代码中的一段,出错的现象很奇怪:
compare函数的返回值是0,但是result运行后的赋值却是2304!
将这段代码单独拿到外面测试,result运行后的赋值却是0,正常。
如果将compare地返回值类型换成short(16位整形),一切正常;
换成int,也一切正常。
不知道是什么原因??

────────────────────────────────────────
 iamxiaohan (潇寒)                    于 2003年12月03日17:09:35 星期三 说道:

什么什么什么呀,说得太详细了~~~ 看不懂~~~ ^_^
你是想做什么?调用bsearch用返回值为char的做比较函数出错是吧?
【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: 一般比较函数的返回至应该设置成int类型,
: 我为了节省空间设置成了char类型(8位整形数),
: 在函数内部比较的时候一切正常,但是作为函数指针放到bsearch中的时候,
: 在bsearch中就出错,不能够将返回至正确的复制,出错的代码是这一段:
: if (!(result = (*compare)(key,mid)))

────────────────────────────────────────
 artist (手艺人)                      于 2003年12月03日17:21:16 星期三 说道:

个人观点:
1 空间不是这么省地,作为函数返回值,即使你设成char型,由于内存分配的对齐需要,
也占用2个或4个字节。
2 你的result是int型吧,不同类型的变量赋值时,建议采用强制类型转换。
用result=(int)(*compare)(key,mid);再试试。
一家之言,仅供参考。
【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: 一般比较函数的返回至应该设置成int类型,
: 我为了节省空间设置成了char类型(8位整形数),
: 在函数内部比较的时候一切正常,但是作为函数指针放到bsearch中的时候,
: 在bsearch中就出错,不能够将返回至正确的复制,出错的代码是这一段:
: if (!(result = (*compare)(key,mid)))

────────────────────────────────────────
 xceman (辉->光阴匆匆似流水)          于 2003年12月03日19:59:16 星期三 说道:

嗯哪,完全同意你的两个观点,
不过是一不小心用错了,现在程序是可以正确运行,因为我将返回值改成int了,
不过还是不明白,如果返回值是char,为什么不行?
即使是对齐,也不应该出现问题,
况且将这段bsearch中的代码放到别的地方就没问题了
【 在 artist (手艺人) 的大作中提到: 】
: 个人观点:
: 1 空间不是这么省地,作为函数返回值,即使你设成char型,由于内存分配的对齐需要,
: 也占用2个或4个字节。
: 2 你的result是int型吧,不同类型的变量赋值时,建议采用强制类型转换。
: 用result=(int)(*compare)(key,mid);再试试。

────────────────────────────────────────
 xceman (辉->光阴匆匆似流水)          于 2003年12月03日19:59:34 星期三 说道:

嘿嘿,你理解的就是我要问的
【 在 iamxiaohan (潇寒) 的大作中提到: 】
: 什么什么什么呀,说得太详细了~~~ 看不懂~~~ ^_^
: 你是想做什么?调用bsearch用返回值为char的做比较函数出错是吧?
: 【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: : 一般比较函数的返回至应该设置成int类型,
: : 我为了节省空间设置成了char类型(8位整形数),
: : 在函数内部比较的时候一切正常,但是作为函数指针放到bsearch中的时候,
: : 在bsearch中就出错,不能够将返回至正确的复制,出错的代码是这一段:
: : if (!(result = (*compare)(key,mid)))

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月03日20:12:49 星期三 说道:

bsearch要的函数指针类型无论如何不能更改
【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: 一般比较函数的返回至应该设置成int类型,
: 我为了节省空间设置成了char类型(8位整形数),
: 在函数内部比较的时候一切正常,但是作为函数指针放到bsearch中的时候,
: 在bsearch中就出错,不能够将返回至正确的复制,出错的代码是这一段:
: if (!(result = (*compare)(key,mid)))

────────────────────────────────────────
 xceman (辉->光阴匆匆似流水)          于 2003年12月03日20:45:04 星期三 说道:

the reason??
【 在 Sun (大灯泡) 的大作中提到: 】
: bsearch要的函数指针类型无论如何不能更改
: 【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: : 一般比较函数的返回至应该设置成int类型,
: : 我为了节省空间设置成了char类型(8位整形数),
: : 在函数内部比较的时候一切正常,但是作为函数指针放到bsearch中的时候,
: : 在bsearch中就出错,不能够将返回至正确的复制,出错的代码是这一段:
: : if (!(result = (*compare)(key,mid)))

────────────────────────────────────────
 iamxiaohan (潇寒)                    于 2003年12月03日20:46:09 星期三 说道:

参数的退压栈问题
【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: 嘿嘿,你理解的就是我要问的
: 【 在 iamxiaohan (潇寒) 的大作中提到: 】
: : 什么什么什么呀,说得太详细了~~~ 看不懂~~~ ^_^
: : 你是想做什么?调用bsearch用返回值为char的做比较函数出错是吧?

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月03日20:54:13 星期三 说道:

因为它就是要
int (*fcmp)(const void*, const void*)
这种类型的函数指针,也是按照这种类型去调用
你改了类型,它不知道,自然配合可能出现问题
至于为什么代码拷贝出来没有问题,可能是库预先编译的执行代码和你自己编译的还是有
些区别吧
【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: the reason??
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : bsearch要的函数指针类型无论如何不能更改

────────────────────────────────────────
 kylix (智贤fans)                     于 2003年12月03日21:14:47 星期三 说道:

也许是老的库文件里面生成.o或.a的时候用的是int *,他改后的源文件
变成char *,但在编译连接时用的是老的库文件,所以可能出现问题
【 在 Sun (大灯泡) 的大作中提到: 】
: 因为它就是要
: int (*fcmp)(const void*, const void*)
: 这种类型的函数指针,也是按照这种类型去调用
: 你改了类型,它不知道,自然配合可能出现问题
: 至于为什么代码拷贝出来没有问题,可能是库预先编译的执行代码和你自己编译的还是有
: 些区别吧
: 【 在 xceman (辉->光阴匆匆似流水) 的大作中提到: 】
: : the reason??

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月03日21:19:59 星期三 说道:

比较奇怪的是,他节省空间的手段是让函数返回值从int到char
这能节省空间吗?
函数返回值是用EAX传的
【 在 kylix (智贤fans) 的大作中提到: 】
: 也许是老的库文件里面生成.o或.a的时候用的是int *,他改后的源文件
: 变成char *,但在编译连接时用的是老的库文件,所以可能出现问题
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 因为它就是要
: : int (*fcmp)(const void*, const void*)
: : 这种类型的函数指针,也是按照这种类型去调用
: : 你改了类型,它不知道,自然配合可能出现问题
: : 至于为什么代码拷贝出来没有问题,可能是库预先编译的执行代码和你自己编译的还是有
: : 些区别吧

────────────────────────────────────────
 iamxiaohan (潇寒)                    于 2003年12月03日21:35:21 星期三 说道:

这到是其次,对于char编译器可以翻译指令为 mov eax , al ; ^_^
关键是int函数指针与char函数指针根本就是不同的类型,在连接程序的时候,对于函
数定位的计算是要出错的,这很可能激出WINDOWS跳出非法内存访问框框,
它没跳已经万幸了 ^_^
【 在 Sun (大灯泡) 的大作中提到: 】
: 比较奇怪的是,他节省空间的手段是让函数返回值从int到char
: 这能节省空间吗?
: 函数返回值是用EAX传的
: 【 在 kylix (智贤fans) 的大作中提到: 】
: : 也许是老的库文件里面生成.o或.a的时候用的是int *,他改后的源文件
: : 变成char *,但在编译连接时用的是老的库文件,所以可能出现问题

────────────────────────────────────────
 hotman (风)                          于 Wed Dec  3 22:35:04 2003 说道:

1,什么叫节省空间?例如是节省磁盘空间或者ROM空间,还是节省运行内存空间?如果是
前者的话——那就把程序写小点,少定义全局变量(这都是占数据段的),如果是后者,
那就少使用内存,例如少申请一块堆中的内存或者函数内部变量尽量少,尤其是大数组。


2,返回值基本上都是使用AX或者EAX返回的,这要看编译器是如何生成了,例如BC31肯定
是AX,VC的肯定是EAX。

3,对于bsearch的参数compare可以强类型转换一下,例如(int (*)(char *, char *))P,
这样就不会导致函数堆栈错误了。

4,谈到边界问题,对于bsearch本来就是要快一些,如果再搞个char,如体系结构中所说
,这可能反而会影响速度了,计算机运算机器字长总比非字长快。是否边界对齐,这可以
从编译器选项中选择,一般优化速度都边界对齐的。


【 在 iamxiaohan 的大作中提到: 】
: 这到是其次,对于char编译器可以翻译指令为 mov eax , al ; ^_^
: 关键是int函数指针与char函数指针根本就是不同的类型,在连接程序的时候,对于函
: 数定位的计算是要出错的,这很可能激出WINDOWS跳出非法内存访问框框,
: 它没跳已经万幸了 ^_^
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 比较奇怪的是,他节省空间的手段是让函数返回值从int到char
: : 这能节省空间吗?
: : 函数返回值是用EAX传的

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日08:09:03 星期四 说道:

mov eax, al了也不能节省空间呀
【 在 iamxiaohan (潇寒) 的大作中提到: 】
: 这到是其次,对于char编译器可以翻译指令为 mov eax , al ; ^_^
: 关键是int函数指针与char函数指针根本就是不同的类型,在连接程序的时候,对于函
: 数定位的计算是要出错的,这很可能激出WINDOWS跳出非法内存访问框框,
: 它没跳已经万幸了 ^_^
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 比较奇怪的是,他节省空间的手段是让函数返回值从int到char
: : 这能节省空间吗?
: : 函数返回值是用EAX传的

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日08:10:45 星期四 说道:

你的意思是调用bsearch的时候强转?
好像应该也不成,那样并没有改变compare函数的实质
【 在 hotman (风) 的大作中提到: 】
: 1,什么叫节省空间?例如是节省磁盘空间或者ROM空间,还是节省运行内存空间?如果是
: 前者的话——那就把程序写小点,少定义全局变量(这都是占数据段的),如果是后者,
: 那就少使用内存,例如少申请一块堆中的内存或者函数内部变量尽量少,尤其是大数组。


: 2,返回值基本上都是使用AX或者EAX返回的,这要看编译器是如何生成了,例如BC31肯定
: 是AX,VC的肯定是EAX。

: 3,对于bsearch的参数compare可以强类型转换一下,例如(int (*)(char *, char *))P,
: 这样就不会导致函数堆栈错误了。


────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日08:22:54 星期四 说道:

不再犯臆想的错误,刚才实验了一下
compare函数必须定义返回值为int,否则编译不能通过,估计xceman也是用了类型强转了
强转后,编译没问题
以char为返回值,最后只用al
16:       char c = 0;
004010B8   mov         byte ptr [ebp-4],0
17:       return c;
004010BC   mov         al,byte ptr [ebp-4]
18:   }
所以bsearch调用compare的结果是取决于此时EAX高24位是什么
【 在 hotman (风) 的大作中提到: 】
: 1,什么叫节省空间?例如是节省磁盘空间或者ROM空间,还是节省运行内存空间?如果是
: 前者的话——那就把程序写小点,少定义全局变量(这都是占数据段的),如果是后者,
: 那就少使用内存,例如少申请一块堆中的内存或者函数内部变量尽量少,尤其是大数组。


: 2,返回值基本上都是使用AX或者EAX返回的,这要看编译器是如何生成了,例如BC31肯定
: 是AX,VC的肯定是EAX。

: 3,对于bsearch的参数compare可以强类型转换一下,例如(int (*)(char *, char *))P,
: 这样就不会导致函数堆栈错误了。


────────────────────────────────────────
 xceman (辉->光阴匆匆似流水)          于 2003年12月04日09:23:10 星期四 说道:

【 在 hotman (风) 的大作中提到: 】
1,什么叫节省空间?例如是节省磁盘空间或者ROM空间,还是节省运行内存空间?如果是
前者的话——那就把程序写小点,少定义全局变量(这都是占数据段的),如果是后者,
那就少使用内存,例如少申请一块堆中的内存或者函数内部变量尽量少,尤其是大数组。
2,返回值基本上都是使用AX或者EAX返回的,这要看编译器是如何生成了,例如BC31肯定
是AX,VC的肯定是EAX。
3,对于bsearch的参数compare可以强类型转换一下,例如(int (*)(char *, char *))P
这样就不会导致函数堆栈错误了。
           _________俺就是这么做地,嘿嘿
4,谈到边界问题,对于bsearch本来就是要快一些,如果再搞个char,如体系结构中所说
,这可能反而会影响速度了,计算机运算机器字长总比非字长快。是否边界对齐,这可以
从编译器选项中选择,一般优化速度都边界对齐的。
【 在 iamxiaohan 的大作中提到: 】
: 这到是其次,对于char编译器可以翻译指令为 mov eax , al ; ^_^
: 关键是int函数指针与char函数指针根本就是不同的类型,在连接程序的时候,对于函
: 数定位的计算是要出错的,这很可能激出WINDOWS跳出非法内存访问框框,
: 它没跳已经万幸了 ^_^
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 比较奇怪的是,他节省空间的手段是让函数返回值从int到char
: : 这能节省空间吗?
: : 函数返回值是用EAX传的

────────────────────────────────────────
 xceman (辉->光阴匆匆似流水)          于 2003年12月04日09:24:53 星期四 说道:

对于节省空间等问题,俺最多是从编译的角度来考虑,
想这样从汇编的角度考虑,俺还不太适应,还得多多学习//blush
【 在 Sun (大灯泡) 的大作中提到: 】
: mov eax, al了也不能节省空间呀
: 【 在 iamxiaohan (潇寒) 的大作中提到: 】
: : 这到是其次,对于char编译器可以翻译指令为 mov eax , al ; ^_^
: : 关键是int函数指针与char函数指针根本就是不同的类型,在连接程序的时候,对于函
: : 数定位的计算是要出错的,这很可能激出WINDOWS跳出非法内存访问框框,
: : 它没跳已经万幸了 ^_^

────────────────────────────────────────
 iamxiaohan (潇寒)                    于 2003年12月04日10:10:06 星期四 说道:

不光是compare的值的问题,如果是返回值那么最多是程序执行有误,而不会跳内存错误,
而这是会存在内存非法访问的问题
【 在 Sun (大灯泡) 的大作中提到: 】
: 不再犯臆想的错误,刚才实验了一下
: compare函数必须定义返回值为int,否则编译不能通过,估计xceman也是用了类型强转了
: 强转后,编译没问题
: 以char为返回值,最后只用al
: 16:       char c = 0;
: 004010B8   mov         byte ptr [ebp-4],0
: 17:       return c;
: 004010BC   mov         al,byte ptr [ebp-4]
: 18:   }
: 所以bsearch调用compare的结果是取决于此时EAX高24位是什么

────────────────────────────────────────
 kylix (智贤fans)                     于 2003年12月04日10:14:14 星期四 说道:

不会节省什么空间,全都是在寄存器里面处理的,我估计
他是想少用个局部变量什么的,呵呵,不过好像没必要啊,这个
东西的内存是堆栈段的。
【 在 Sun (大灯泡) 的大作中提到: 】
: 比较奇怪的是,他节省空间的手段是让函数返回值从int到char
: 这能节省空间吗?
: 函数返回值是用EAX传的
: 【 在 kylix (智贤fans) 的大作中提到: 】
: : 也许是老的库文件里面生成.o或.a的时候用的是int *,他改后的源文件
: : 变成char *,但在编译连接时用的是老的库文件,所以可能出现问题

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日10:20:28 星期四 说道:

内存非法访问地没有呀,where?
【 在 iamxiaohan (潇寒) 的大作中提到: 】
: 不光是compare的值的问题,如果是返回值那么最多是程序执行有误,而不会跳内存错误,
: 而这是会存在内存非法访问的问题
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 不再犯臆想的错误,刚才实验了一下
: : compare函数必须定义返回值为int,否则编译不能通过,估计xceman也是用了类型强转了
: : 强转后,编译没问题
: : 以char为返回值,最后只用al
: : 16:       char c = 0;
: : 004010B8   mov         byte ptr [ebp-4],0
: : 17:       return c;

────────────────────────────────────────
 iamxiaohan (潇寒)                    于 2003年12月04日10:22:57 星期四 说道:

int与char型函数的内存布局是不同的,他们被link函数重定位,函数指针作为参数是通
过,压栈实现的。本来要用int的栈,现在用了char栈~~~
不信,可以自己写bsearch的实现函数,在windows下,马上就有内存错误框弹出 ^_^
【 在 Sun (大灯泡) 的大作中提到: 】
: 内存非法访问地没有呀,where?
: 【 在 iamxiaohan (潇寒) 的大作中提到: 】
: : 不光是compare的值的问题,如果是返回值那么最多是程序执行有误,而不会跳内存错误,
: : 而这是会存在内存非法访问的问题

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日10:25:49 星期四 说道:

【 在 iamxiaohan (潇寒) 的大作中提到: 】
: int与char型函数的内存布局是不同的,他们被link函数重定位,函数指针作为参数是通
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^有根据吗?
  对于函数指针来说,就是一个32b的地址而已,不管它是什么类型、什么参数
  只不过编译器检查一下类型是否匹配
: 过,压栈实现的。本来要用int的栈,现在用了char栈~~~
: 不信,可以自己写bsearch的实现函数,在windows下,马上就有内存错误框弹出 ^_^
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 内存非法访问地没有呀,where?

────────────────────────────────────────
 iamxiaohan (潇寒)                    于 2003年12月04日10:26:50 星期四 说道:

用objdump可以看
【 在 Sun (大灯泡) 的大作中提到: 】
【 在 iamxiaohan (潇寒) 的大作中提到: 】
: int与char型函数的内存布局是不同的,他们被link函数重定位,函数指针作为参数是通
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^有根据吗?
  对于函数指针来说,就是一个32b的地址而已,不管它是什么类型、什么参数
  只不过编译器检查一下类型是否匹配
: 过,压栈实现的。本来要用int的栈,现在用了char栈~~~
: 不信,可以自己写bsearch的实现函数,在windows下,马上就有内存错误框弹出 ^_^
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 内存非法访问地没有呀,where?

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日10:41:22 星期四 说道:

这样一个程序
main()
{
    char ch[100] = {0};
    char a=1;
    bsearch(&a, ch, 100, 1, (int(*)(const void*, const void*))comp);
    bsearch(&a, ch, 100, 1, comp1);
    return 0;
}
char comp(const void* a, const void* b)
{
    char c = 0;
    return c;
}
int comp1(const void* a, const void* b)
{
    int i = 0;
    return i;
}
main()的汇编代码:
11:       bsearch(&a, ch, 100, 1, (int(*)(const void*, const void*))comp);
00401055   push        offset @ILT+5(_comp) (0040100a)
0040105A   push        1
0040105C   push        64h
0040105E   lea         eax,[ebp-64h]
00401061   push        eax
00401062   lea         ecx,[ebp-68h]
00401065   push        ecx
00401066   call        bsearch (004010d0)
0040106B   add         esp,14h
12:       bsearch(&a, ch, 100, 1, comp1);
0040106E   push        offset @ILT+10(_comp1) (0040100f)
00401073   push        1
00401075   push        64h
00401077   lea         edx,[ebp-64h]
0040107A   push        edx
0040107B   lea         eax,[ebp-68h]
0040107E   push        eax
0040107F   call        bsearch (004010d0)
00401084   add         esp,14h
comp的
18:       char c = 0;
004010B8   mov         byte ptr [ebp-4],0
19:       return c;
004010BC   mov         al,byte ptr [ebp-4]
comp1的
24:       int i = 0;
0040D548   mov         dword ptr [ebp-4],0
25:       return i;
0040D54F   mov         eax,dword ptr [ebp-4]
26:   }
bsearch的
59:                           if (!(result = (*compare)(key,mid)))
00401136   mov         ecx,dword ptr [mid]
00401139   push        ecx
0040113A   mov         edx,dword ptr [key]
0040113D   push        edx
0040113E   call        dword ptr [compare]
00401141   add         esp,8
00401144   mov         dword ptr [result],eax
00401147   cmp         dword ptr [result],0
0040114B   jne         bsearch+82h (00401152)
60:                                   return(mid);
0040114D   mov         eax,dword ptr [mid]
【 在 iamxiaohan (潇寒) 的大作中提到: 】
: 用objdump可以看
: 【 在 Sun (大灯泡) 的大作中提到: 】
: 【 在 iamxiaohan (潇寒) 的大作中提到: 】
: : int与char型函数的内存布局是不同的,他们被link函数重定位,函数指针作为参数是通
:   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^有根据吗?
:   对于函数指针来说,就是一个32b的地址而已,不管它是什么类型、什么参数
:   只不过编译器检查一下类型是否匹配
: : 过,压栈实现的。本来要用int的栈,现在用了char栈~~~

────────────────────────────────────────
 deem (沙丘男爵)                      于 2003年12月04日13:57:50 星期四 说道:

这个 asm dump 不错,叫什么名字?每次我都用objdump,还要自己和
sourcecode对上,这个看上去不用。
【 在 Sun (大灯泡) 的大作中提到: 】
: 这样一个程序
: main()
: {
:     char ch[100] = {0};
:     char a=1;
:     bsearch(&a, ch, 100, 1, (int(*)(const void*, const void*))comp);
:     bsearch(&a, ch, 100, 1, comp1);
:     return 0;
: }
: char comp(const void* a, const void* b)

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月04日14:03:08 星期四 说道:

【 在 Sun (大灯泡) 的大作中提到: 】
: 不再犯臆想的错误,刚才实验了一下
: compare函数必须定义返回值为int,否则编译不能通过,估计xceman也是用了类型强转了
: 强转后,编译没问题
: 以char为返回值,最后只用al
: 16:       char c = 0;
: 004010B8   mov         byte ptr [ebp-4],0
: 17:       return c;
: 004010BC   mov         al,byte ptr [ebp-4]
: 18:   }
: 所以bsearch调用compare的结果是取决于此时EAX高24位是什么
这句话让我想起了如果把 char 返回值赋予 int i 怎么样呢?经验告诉我们明显能得
到正确结果的,那么编译器又是怎么做到的?下面这几行代码表明了大案:
如果将char或short型函数返回值赋予int型变量,编译器先将返回结果 al或ax 进行
符号扩展(movsx   eax, al/ax),然后再进行赋值。
bsearch中,由于comp的返回值被声明为int型,因此 al 没有被符号扩展,而整个eax
直接被当作结果,于是高24位是没意义的。
注意 main 中 对 i 和 j 赋值对应的汇编代码:
对i赋值时作了扩展,而对j时没有,因而j的结果是错误的。
///////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
char foo(void) { return 0; }
int (*bar)(void) = (int(*)(void)) (foo);
int main(int argc, char* argv[])
{
    int i, j;
    i = foo();
    j = bar();
    return 0;
}
//////////////////////////////////////////////////////////////////////////
PUBLIC  ?foo@@YADXZ                 ; foo
PUBLIC  ?bar@@3P6AHXZA                  ; bar
_DATA   SEGMENT
?bar@@3P6AHXZA DD FLAT:?foo@@YADXZ          ; bar
_DATA   ENDS
_TEXT   SEGMENT
?foo@@YADXZ PROC NEAR                   ; foo
; 6    : char foo(void) { return 0; }
    push    ebp
    mov ebp, esp
    xor al, al
    pop ebp
    ret 0
?foo@@YADXZ ENDP                    ; foo
_TEXT   ENDS
PUBLIC  _main
_TEXT   SEGMENT
_i$ = -4
_j$ = -8
_main   PROC NEAR
; 11   : {
    push    ebp
    mov ebp, esp
    sub esp, 8
; 12   :    int i, j;
; 13   :    
; 14   :    i = foo();
    call    ?foo@@YADXZ             ; foo
    movsx   eax, al
    mov DWORD PTR _i$[ebp], eax
; 15   :    j = bar();
    call    DWORD PTR ?bar@@3P6AHXZA        ; bar
    mov DWORD PTR _j$[ebp], eax
; 16   : 
; 17   :    return 0;
    xor eax, eax
; 18   : }
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日17:08:14 星期四 说道:

Visual Studio 6.0, haha
【 在 deem (沙丘男爵) 的大作中提到: 】
: 这个 asm dump 不错,叫什么名字?每次我都用objdump,还要自己和
: sourcecode对上,这个看上去不用。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 这样一个程序
: : main()
: : {
: :     char ch[100] = {0};
: :     char a=1;

────────────────────────────────────────
 hotman (风)                          于 Thu Dec  4 18:06:12 2003 说道:

呵呵,我当然要用过才能敢下结论了:-)
1,VC中
#include <search.h>
#include <string.h>
#include <stdio.h>

char compare( char **arg1, char **arg2 ); /* Declare a function for compare */


void main( int argc, char **argv )
{
   char **result;
   char *key = "cat";
   int i;

   /* Sort using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), (int (*)(const 
   void*, const void*))compare );

   for( i = 0; i < argc; ++i )    /* Output sorted list */
      printf( "%s ", argv[i] );

   /* Find the word "cat" using a binary search algorithm: */
   result = (char **)bsearch( (char *) &key, (char *)argv, argc,
                              sizeof( char * ), (int (*)(const void*, const vo
id*))compare );
   if( result )
      printf( "\n%s found at %Fp\n", *result, result );
   else
      printf( "\nCat not found!\n" );
}

//int compare( char **arg1, char **arg2 )
char compare( char **arg1, char **arg2 )
{
   /* Compare all of both strings: */
   return _strcmpi( *arg1, *arg2 );
}

2,BC31中:
#include <search.h>
#include <string.h>
#include <stdio.h>

char compare( char **arg1, char **arg2 ); /* Declare a function for compare */


void main( int argc, char **argv )
{
   char **result;
   char *key = "cat";
   int i;

   /* Sort using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), (int (*)(const 
   void*, const void*))compare );

   for( i = 0; i < argc; ++i )    /* Output sorted list */
      printf( "%s ", argv[i] );

   /* Find the word "cat" using a binary search algorithm: */
   result = (char **)bsearch( (char *) &key, (char *)argv, argc,
                              sizeof( char * ), (int (*)(const void*, const vo
id*))compare );
   if( result )
      printf( "\n%s found at %Fp\n", *result, result );
   else
      printf( "\nCat not found!\n" );
}

//int compare( char **arg1, char **arg2 )
char compare( char **arg1, char **arg2 )
{
   /* Compare all of both strings: */
   return strcmp( *arg1, *arg2 );
}

3,GCC中
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char compare( char **arg1, char **arg2 ); /* Declare a function for compare */


int main( int argc, char **argv )
{
   char **result;
   char *key = "cat";
   int i;

   /* Sort using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), (int (*)(const 
   void*, const void*))compare );

   for( i = 0; i < argc; ++i )    /* Output sorted list */
      printf( "%s ", argv[i] );

   /* Find the word "cat" using a binary search algorithm: */
   result = (char **)bsearch( (char *) &key, (char *)argv, argc,
                              sizeof( char * ), (int (*)(const void*, const vo
id*))compare );
   if( result )
      printf( "\n%s found at %Fp\n", *result, result );
   else
      printf( "\nCat not found!\n" );
      
   return 0;
}

//int compare( char **arg1, char **arg2 )
char compare( char **arg1, char **arg2 )
{
   /* Compare all of both strings: */
   return _strcmpi( *arg1, *arg2 );
}


我想应该基本上覆盖了当前一般流行的编译器了吧。

【 在 Sun 的大作中提到: 】
: 不再犯臆想的错误,刚才实验了一下
: compare函数必须定义返回值为int,否则编译不能通过,估计xceman也是用了类型强..
: 强转后,编译没问题
: 以char为返回值,最后只用al
: 16:       char c = 0;
: 004010B8   mov         byte ptr [ebp-4],0
: 17:       return c;
: 004010BC   mov         al,byte ptr [ebp-4]
: 18:   }
: 所以bsearch调用compare的结果是取决于此时EAX高24位是什么
: 【 在 hotman (风) 的大作中提到: 】
: : 1,什么叫节省空间?例如是节省磁盘空间或者ROM空间,还是节省运行内存空间?..
: : 前者的话——那就把程序写小点,少定义全局变量(这都是占数据段的),如果是..
: : 那就少使用内存,例如少申请一块堆中的内存或者函数内部变量尽量少,尤其是大..
: : 
: : 
: : 2,返回值基本上都是使用AX或者EAX返回的,这要看编译器是如何生成了,例如BC..
: : 是AX,VC的肯定是EAX。
: : 
: : 3,对于bsearch的参数compare可以强类型转换一下,例如(int (*)(char *, char..
: (以下引言省略...)

────────────────────────────────────────
 deem (沙丘男爵)                      于 2003年12月04日18:11:49 星期四 说道:

^_^,看错了,我以为是tsearch,原来是bsearch,搞错平台了
【 在 Sun (大灯泡) 的大作中提到: 】
: Visual Studio 6.0, haha
: 【 在 deem (沙丘男爵) 的大作中提到: 】
: : 这个 asm dump 不错,叫什么名字?每次我都用objdump,还要自己和
: : sourcecode对上,这个看上去不用。

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日18:13:22 星期四 说道:

从前面分析看,你这个程序好使只能是因为运气好
【 在 hotman (风) 的大作中提到: 】
: 呵呵,我当然要用过才能敢下结论了:-)
: 1,VC中
: #include <search.h>
: #include <string.h>
: #include <stdio.h>

: char compare( char **arg1, char **arg2 ); /* Declare a function for compare */


: void main( int argc, char **argv )
: {

────────────────────────────────────────
 hotman (风)                          于 Thu Dec  4 18:42:33 2003 说道:

VC中,调试你的程序如下所示:同样可以工作
#include <search.h>

char comp(const void* a, const void* b);
int comp1(const void* a, const void* b);
main()
{
    char ch[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    char a=9;
    
    char *r = (char*)bsearch(&a, ch, sizeof(ch), sizeof(char), (int(*)(const v
oid*, const void*))comp);
    //bsearch(&a, ch, 100, 1, comp1);
    return 0;
}

char comp(const void* a, const void* b)
{
    //char c = 0;
    //return c;
    return (*(char*)a - *(char*)b);
}

int comp1(const void* a, const void* b)
{
    int i = 0;
    return i;
}


【 在 Sun 的大作中提到: 】
: 这样一个程序
: main()
: {
:     char ch[100] = {0};
:     char a=1;
:     bsearch(&a, ch, 100, 1, (int(*)(const void*, const void*))comp);
:     bsearch(&a, ch, 100, 1, comp1);
:     return 0;
: }
: char comp(const void* a, const void* b)
: {
:     char c = 0;
:     return c;
: }
: int comp1(const void* a, const void* b)
: {
:     int i = 0;
:     return i;
: }
: main()的汇编代码:
: (以下引言省略...)

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月04日18:57:07 星期四 说道:

19:       return (*(char*)a - *(char*)b);
0040D57C   mov         eax,dword ptr [ebp+8]
0040D57F   movsx       eax,byte ptr [eax]
0040D582   mov         ecx,dword ptr [ebp+0Ch]
0040D585   movsx       edx,byte ptr [ecx]
0040D588   sub         eax,edx
20:   }
为了计算减法,EAX全用上了,所以100%没问题
但是,这么做绝对是危险的。毛主席教导我们说,一切事情不能只看表面现象
从本质看,这样做是非常危险的,只要编译器换一种实现方法,就会出问题
这种用法并不符合ANSI C
【 在 hotman (风) 的大作中提到: 】
: VC中,调试你的程序如下所示:同样可以工作
: #include <search.h>

: char comp(const void* a, const void* b);
: int comp1(const void* a, const void* b);
: main()
: {
:     char ch[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
:     char a=9;
:     
:     char *r = (char*)bsearch(&a, ch, sizeof(ch), sizeof(char), (int(*)(const v

────────────────────────────────────────
 iamxiaohan (潇寒·System Programmer ^_^)  于 2003年12月04日21:55:01 星期四 说道:

出什么问题?
【 在 Sun (大灯泡) 的大作中提到: 】
: 19:       return (*(char*)a - *(char*)b);
: 0040D57C   mov         eax,dword ptr [ebp+8]
: 0040D57F   movsx       eax,byte ptr [eax]
: 0040D582   mov         ecx,dword ptr [ebp+0Ch]
: 0040D585   movsx       edx,byte ptr [ecx]
: 0040D588   sub         eax,edx
: 20:   }
: 为了计算减法,EAX全用上了,所以100%没问题
: 但是,这么做绝对是危险的。毛主席教导我们说,一切事情不能只看表面现象

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月05日00:03:48 星期五 说道:

xceman那样的问题
【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: 出什么问题?
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 19:       return (*(char*)a - *(char*)b);
: : 0040D57C   mov         eax,dword ptr [ebp+8]
: : 0040D57F   movsx       eax,byte ptr [eax]
: : 0040D582   mov         ecx,dword ptr [ebp+0Ch]
: : 0040D585   movsx       edx,byte ptr [ecx]
: : 0040D588   sub         eax,edx
: : 20:   }
: : 为了计算减法,EAX全用上了,所以100%没问题
: : 但是,这么做绝对是危险的。毛主席教导我们说,一切事情不能只看表面现象

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月05日09:22:58 星期五 说道:

我在 gcc version 3.2.1 [FreeBSD] 20021119 (release) 下也试了一下
结果是对于gcc来说是没有问题的,原因在于即使返回值是char或short,
gcc使用的仍然是整个eax,而不是只操作 al。这与vc编译器不同。
也就是说xceman的问题在gcc下应该不会出现,谁验证一下,hehe
源代码:
char foo(void) { return 0; }
int  (*bar)(void) = (int (*)(void))foo;
int main(void)
{
    int i, j;
    i = j = 0xCCCCCCCC;
    i = foo();
    j = bar();
    printf("i = 0x%08X, j = 0x%08X\n", i, j);
    return 0;
}
gcc -S foo.c得到 foo.s,部分内容如下:
.globl foo
    .type foo,@function
foo:
    pushl   %ebp
    movl    %esp, %ebp
    movl    $0, %eax
    leave
    ret
.globl main
    .type main,@function
main:
    ...
    call foo
    movsbl  %al,%eax            ;由于是char到int的转换,符号扩展仍然进行了
    movl    %eax, -4(%ebp)
    movl    bar, %eax
    call    *%eax
    movl    %eax, -8(%ebp)
结果是:
%./foo
i = 0x00000000, j = 0x00000000
%
而vc则是
i = 0x00000000, j = 0xCCCCCC00
Press any key to continue
【 在 Sun (大灯泡) 的大作中提到: 】
: 从前面分析看,你这个程序好使只能是因为运气好
: 【 在 hotman (风) 的大作中提到: 】
: : 呵呵,我当然要用过才能敢下结论了:-)
: : 1,VC中
: : #include <search.h>
: : #include <string.h>
: : #include <stdio.h>
: : char compare( char **arg1, char **arg2 ); /* Declare a function for compare */

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月05日09:27:24 星期五 说道:

3054看了吗?还有上面这篇
我觉得问题已经清晰了呀,还是我的分析有问题?
【 在 Sun (大灯泡) 的大作中提到: 】
: xceman那样的问题
: 【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: : 出什么问题?

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月05日09:31:28 星期五 说道:

结论就是:
依赖具体的编译器实现。可能同种编译器不同参数也会产生不同效果
所以这样的用法要禁止,它是不符合C标准的
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 3054看了吗?还有上面这篇
: 我觉得问题已经清晰了呀,还是我的分析有问题?
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : xceman那样的问题

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月05日09:44:59 星期五 说道:

这就是了,编译器的不同效果就在于对返回值eax的处理上,
gcc将char或short放入eax,而vc则直接放入al或ax。其他
的编译器大概不外乎这两种处理之一。
【 在 Sun (大灯泡) 的大作中提到: 】
: 结论就是:
: 依赖具体的编译器实现。可能同种编译器不同参数也会产生不同效果
: 所以这样的用法要禁止,它是不符合C标准的
: 【 在 lofe (〖感激生活〗) 的大作中提到: 】
: : 3054看了吗?还有上面这篇
: : 我觉得问题已经清晰了呀,还是我的分析有问题?

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月05日09:48:59 星期五 说道:

也许还有用栈传返回值的……
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 这就是了,编译器的不同效果就在于对返回值eax的处理上,
: gcc将char或short作符号扩展后返回eax,而vc则直接返回
: al或ax。其他的编译器大概不外乎这两种处理之一。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 结论就是:
: : 依赖具体的编译器实现。可能同种编译器不同参数也会产生不同效果
: : 所以这样的用法要禁止,它是不符合C标准的

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月05日09:56:07 星期五 说道:

也许,不过那样得到的代码比如库函数,兼容性很不好吧,
因为大多数别的编译器都认为函数调用的返回结果在eax中
我推测:要能够调用gnu的库函数或者winapi,编译器就必须
用eax返回结果,不知道对不对,不要砍我,hehe
【 在 Sun (大灯泡) 的大作中提到: 】
也许还有用栈传返回值的……
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 这就是了,编译器的不同效果就在于对返回值eax的处理上,
: gcc将char或short作符号扩展后返回eax,而vc则直接返回
: al或ax。其他的编译器大概不外乎这两种处理之一。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 结论就是:
: : 依赖具体的编译器实现。可能同种编译器不同参数也会产生不同效果
: : 所以这样的用法要禁止,它是不符合C标准的

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月05日10:09:58 星期五 说道:

gnu的库函数也是可以重新编译的呀。:)
再说,咱不是说一定会这样,而是说可能如何
也许在另一个架构的CPU之下,还会有更出乎我们意料的实现方法
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 也许,不过那样得到的代码比如库函数,兼容性很不好吧,
: 因为大多数别的编译器都认为函数调用的返回结果在eax中
: 我推测:要能够调用gnu的库函数或者winapi,编译器就必须
: 用eax返回结果,不知道对不对,不要砍我,hehe
: 【 在 Sun (大灯泡) 的大作中提到: 】
: 也许还有用栈传返回值的……
: 【 在 lofe (〖感激生活〗) 的大作中提到: 】
: : 这就是了,编译器的不同效果就在于对返回值eax的处理上,

────────────────────────────────────────
 iamxiaohan (潇寒·System Programmer ^_^)  于 2003年12月05日13:56:08 星期五 说道:

bsearch本来就是依赖编译器的实现函数,
一切以void*做为通用参量的函数都是与编译器级具体的计算机体系结构相关的,
它们不能产生可移植代码
【 在 Sun (大灯泡) 的大作中提到: 】
: 结论就是:
: 依赖具体的编译器实现。可能同种编译器不同参数也会产生不同效果
: 所以这样的用法要禁止,它是不符合C标准的
: 【 在 lofe (〖感激生活〗) 的大作中提到: 】
: : 3054看了吗?还有上面这篇
: : 我觉得问题已经清晰了呀,还是我的分析有问题?

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月05日14:26:14 星期五 说道:

【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: bsearch本来就是依赖编译器的实现函数,
    bsearch是c的标准库函数,只要你按照c标准来调用,就不依赖于编译器。
: 一切以void*做为通用参量的函数都是与编译器级具体的计算机体系结构相关的,
: 它们不能产生可移植代码
    void*参数可以说是为了简化接口,尤其是在callback中,它是让这个函数的
实现者来解释其意义,而跟编译器没有任何关系。
   eg. int main(int argc, void *p) {return 0;} 显然是可以移植的
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 结论就是:
: : 依赖具体的编译器实现。可能同种编译器不同参数也会产生不同效果
: : 所以这样的用法要禁止,它是不符合C标准的

────────────────────────────────────────
 iamxiaohan (潇寒·System Programmer ^_^)  于 2003年12月05日14:32:49 星期五 说道:

不能这样说,
bserach不是ANSI C的标准所规定的,只是编译器厂商提供的库,
关键是里面设计到了这样一个void* p的使用,
考虑一下bsearch的实现,
因为是void*,所以编译器无法知道指针的所指对象的大小,也就是指针所指对象
所占的内存,这就只能过过程序指定来实现了,
对于 void* p ;
如果是char,那么 p++ 就是移动一个字节,
如果是 int,那么在 intel i386 结构上 p++ 就是 
p = (void*)( (unsigned int)p + 4 ) ;
这是按照intel以低低高高的存放原理实现的,
但在其它cpu结构下,不一定是以低低高高实现的,因此使用上要出问题的
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: : bsearch本来就是依赖编译器的实现函数,
:     bsearch是c的标准库函数,只要你按照c标准来调用,就不依赖于编译器。
: : 一切以void*做为通用参量的函数都是与编译器级具体的计算机体系结构相关的,
: : 它们不能产生可移植代码
:     void*参数可以说是为了简化接口,尤其是在callback中,它是让这个函数的
: 实现者来解释其意义,而跟编译器没有任何关系。
:    eg. int main(int argc, void *p) {return 0;} 显然是可以移植的

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月05日15:31:56 星期五 说道:

【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: 不能这样说,
: bserach不是ANSI C的标准所规定的,只是编译器厂商提供的库,
   刚才特地上搜索了一下,bsearch 是ANSI C的标准函数,位于stdlib,
就像malloc一样.

: 关键是里面设计到了这样一个void* p的使用,
: 考虑一下bsearch的实现,
: 因为是void*,所以编译器无法知道指针的所指对象的大小,也就是指针所指对象
: 所占的内存,这就只能过过程序指定来实现了,
: 对于 void* p ;
: 如果是char,那么 p++ 就是移动一个字节,
: 如果是 int,那么在 intel i386 结构上 p++ 就是 
: p = (void*)( (unsigned int)p + 4 ) ;
: 这是按照intel以低低高高的存放原理实现的,
  你说的这些都是对的,compare是我们自己提供的,因而我们知道。
而实际上 bsearch也知道void *p 的大小,因为 base有了,size 为
每个元素的占据的空间,一共有nmemb个元素,剩下的就是指针运算,
遍历了。
man bsearch:
SYNOPSIS
       #include <stdlib.h>
       void *bsearch(const void *key, const void *base, size_t nmemb,
              size_t size, int (*compar)(const void *, const void *));
DESCRIPTION
       The  bsearch() function searches an array of nmemb objects, the initial
       member of which is pointed to by base, for a member  that  matches  the
       object  pointed  to  by  key.   The size of each member of the array is
       specified by size.

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月05日16:22:33 星期五 说道:

问题不是出在void*,而是出在作为返回值的char
【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: 不能这样说,
: bserach不是ANSI C的标准所规定的,只是编译器厂商提供的库,
: 关键是里面设计到了这样一个void* p的使用,
: 考虑一下bsearch的实现,
: 因为是void*,所以编译器无法知道指针的所指对象的大小,也就是指针所指对象
: 所占的内存,这就只能过过程序指定来实现了,
: 对于 void* p ;
: 如果是char,那么 p++ 就是移动一个字节,
: 如果是 int,那么在 intel i386 结构上 p++ 就是 
: p = (void*)( (unsigned int)p + 4 ) ;
: 这是按照intel以低低高高的存放原理实现的,

────────────────────────────────────────
 iamxiaohan (潇寒·System Programmer ^_^)  于 2003年12月05日22:23:51 星期五 说道:

我是说另外一个问题,是关于void*的移值性问题。
【 在 Sun (大灯泡) 的大作中提到: 】
: 问题不是出在void*,而是出在作为返回值的char
: 【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: : 不能这样说,
: : bserach不是ANSI C的标准所规定的,只是编译器厂商提供的库,
: : 关键是里面设计到了这样一个void* p的使用,
: : 考虑一下bsearch的实现,
: : 因为是void*,所以编译器无法知道指针的所指对象的大小,也就是指针所指对象
: : 所占的内存,这就只能过过程序指定来实现了,
: : 对于 void* p ;
: : 如果是char,那么 p++ 就是移动一个字节,

────────────────────────────────────────
 iamxiaohan (潇寒·System Programmer ^_^)  于 2003年12月05日22:24:35 星期五 说道:

同STL一样,只是一种规定,每个编译器厂自行提供在特定平台下的实现
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: : 不能这样说,
: : bserach不是ANSI C的标准所规定的,只是编译器厂商提供的库,
:    刚才特地上搜索了一下,bsearch 是ANSI C的标准函数,位于stdlib,
: 就像malloc一样.
: 。
: : 关键是里面设计到了这样一个void* p的使用,
: : 考虑一下bsearch的实现,
: : 因为是void*,所以编译器无法知道指针的所指对象的大小,也就是指针所指对象

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月05日22:59:13 星期五 说道:

void*应该不会有移植问题吧?这个是纯C的
【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: 我是说另外一个问题,是关于void*的移值性问题。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 问题不是出在void*,而是出在作为返回值的char

────────────────────────────────────────
 iamxiaohan (潇寒·System Programmer ^_^)  于 2003年12月06日07:29:39 星期六 说道:

C语言不是JAVA,在语法上就不是可移植的。
对于void*,关键就是内存定位不可移植,在低低高高的体系结构的机子上,
它是以+定位,在不是低低高高的体系结构上,它以-定位,因此,你写的程序
就不能在两个体系结构不同的机器上移植。
【 在 Sun (大灯泡) 的大作中提到: 】
: void*应该不会有移植问题吧?这个是纯C的
: 【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: : 我是说另外一个问题,是关于void*的移值性问题。

────────────────────────────────────────
 artist (手艺人)                      于 2003年12月06日10:45:55 星期六 说道:

个人认为:
1 C程序也好,Java程序也好,要想移植,都需要在目标体系结构的机器上重新编译。
  毕竟C和Java都是高级语言,不能直接在目标机上运行。
2 Java所谓的移植性好,也是指将Java代码统统编译成通用中间形式,大概叫Java 
  bytecode 吧,而各种目标机都有自己的bytecode解释器,解释出来的还是各自的机
  器码。
3 高级语言程序一般都是可移植的,只要有对应目标机的编译器。编译器越强大,移植
  越方便。
一家之言,仅供参考。
【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: C语言不是JAVA,在语法上就不是可移植的。
: 对于void*,关键就是内存定位不可移植,在低低高高的体系结构的机子上,
: 它是以+定位,在不是低低高高的体系结构上,它以-定位,因此,你写的程序
: 就不能在两个体系结构不同的机器上移植。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : void*应该不会有移植问题吧?这个是纯C的

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月06日12:38:02 星期六 说道:

好像不全对。
除非你对int或者float这样的sizeof>1的类型的存储空间进行逐字节的操作,否则是不会
遇到高高低低的问题的(这个学名叫big end...和small end...., end开头的单词,具体
怎么拼忘了,手头也查不到,谁知道?)。高高低低的问题已经通过类型进行隐藏了。
比如:
int i;
void* p= (void*)&i;
*(int*)p = 12345;
在任何计算机上面的语句都是有效的
【 在 iamxiaohan (潇寒·System Programmer 
^_^) 的大作中提到: 】: C语言不是JAVA,在语法上就不是可移植的。
: 对于void*,关键就是内存定位不可移植,在低低高高的体系结构的机子上,
: 它是以+定位,在不是低低高高的体系结构上,它以-定位,因此,你写的程序
: 就不能在两个体系结构不同的机器上移植。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : void*应该不会有移植问题吧?这个是纯C的

────────────────────────────────────────
 deem (沙丘男爵)                      于 2003年12月06日14:25:52 星期六 说道:

BIG endian
little endian
【 在 Sun (大灯泡) 的大作中提到: 】
: 好像不全对。
: 除非你对int或者float这样的sizeof>1的类型的存储空间进行逐字节的操作,否则是不会
: 遇到高高低低的问题的(这个学名叫big end...和small end...., end开头的单词,具体
: 怎么拼忘了,手头也查不到,谁知道?)。高高低低的问题已经通过类型进行隐藏了。
: 比如:
: int i;
: void* p= (void*)&i;
: *(int*)p = 12345;
: 在任何计算机上面的语句都是有效的

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月06日15:02:30 星期六 说道:

概念问题,原来你说的是二进制上的跨平台问题。
移植是指源码级的吧?
没有人能用C直接写出二进制通用程序,k&r估计也不能。
否则就不会有com,corba
【 在 iamxiaohan (潇寒·System Programmer ^_^) 的大作中提到: 】
: 同STL一样,只是一种规定,每个编译器厂自行提供在特定平台下的实现
: 【 在 lofe (〖感激生活〗) 的大作中提到: 】
: :    刚才特地上搜索了一下,bsearch 是ANSI C的标准函数,位于stdlib,
: : 就像malloc一样.
: : 。

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月06日15:07:42 星期六 说道:

只有一个例外,不同平台之间的通信问题,比如tcp/ip,存在网络字节顺序问题,:-)
【 在 Sun (大灯泡) 的大作中提到: 】
: 好像不全对。
: 除非你对int或者float这样的sizeof>1的类型的存储空间进行逐字节的操作,否则是不会
: 遇到高高低低的问题的(这个学名叫big end...和small end...., end开头的单词,具体
: 怎么拼忘了,手头也查不到,谁知道?)。高高低低的问题已经通过类型进行隐藏了。
: 比如:
: int i;
: void* p= (void*)&i;
: *(int*)p = 12345;
: 在任何计算机上面的语句都是有效的

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月06日15:11:03 星期六 说道:

这就是对sizeof>1的进行逐字节的操作呀
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 只有一个例外,不同平台之间的通信问题,比如tcp/ip,存在网络字节顺序问题,:-)
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 好像不全对。
: : 除非你对int或者float这样的sizeof>1的类型的存储空间进行逐字节的操作,否则是不会
: : 遇到高高低低的问题的(这个学名叫big end...和small end...., end开头的单词,具体
: : 怎么拼忘了,手头也查不到,谁知道?)。高高低低的问题已经通过类型进行隐藏了。
: : 比如:
: : int i;
: : void* p= (void*)&i;

────────────────────────────────────────
 lofe (〖感激生活〗)                  于 2003年12月06日15:23:26 星期六 说道:

想了又想,好像你刚好写反了,^_^
【 在 Sun (大灯泡) 的大作中提到: 】
: 这就是对sizeof>1的进行逐字节的操作呀
                        ~~~~~~~~~~~~既然是逐字节,那就相当于sizeof==1了,:-)
程序设计实践 8.6节专门讨论了这个移植问题,解决办法是:
  写可移植的代码,总按照正规的顺序写出各个字节,(在另一端)再
一次一个字节的读回,把数据重装起来
  这个方法也可以推广到结构。。。
: 【 在 lofe (〖感激生活〗) 的大作中提到: 】
: : 只有一个例外,不同平台之间的通信问题,比如tcp/ip,存在网络字节顺序问题,:-)

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月06日15:34:03 星期六 说道:

不是写反了,是不严密
我的意思是比如
int i=1;
char* p = (char*)&i;
*p = 0;
这样将使i==0,在x86上。但是这样就默认了x86的endian
【 在 lofe (〖感激生活〗) 的大作中提到: 】
: 想了又想,好像你刚好写反了,^_^
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 这就是对sizeof>1的进行逐字节的操作呀
:                         ~~~~~~~~~~~~既然是逐字节,那就相当于sizeof==1了,:-)
: 程序设计实践 8.6节专门讨论了这个移植问题,解决办法是:
:   写可移植的代码,总按照正规的顺序写出各个字节,(在另一端)再
: 一次一个字节的读回,把数据重装起来

────────────────────────────────────────
 ecomer (ecomer)                      于 2003年12月06日18:38:03 星期六 说道:

char* p = (char*)i;是什么意思?
觉得应该是 char*p = (char*)(&i); 这样p才能取道i的地址。
【 在 Sun (大灯泡) 的大作中提到: 】
: 不是写反了,是不严密
: 我的意思是比如
: int i=1;
: char* p = (char*)i;
: *p = 0;
: 这样将使i==0,在x86上。但是这样就默认了x86的endian

────────────────────────────────────────
 Sun (大灯泡)                         于 2003年12月06日20:35:54 星期六 说道:

是少了一个&,谢谢
【 在 ecomer (ecomer) 的大作中提到: 】
: char* p = (char*)i;是什么意思?
: 觉得应该是 char*p = (char*)(&i); 这样p才能取道i的地址。
: 【 在 Sun (大灯泡) 的大作中提到: 】
: : 不是写反了,是不严密
: : 我的意思是比如
: : int i=1;
: : char* p = (char*)i;
: : *p = 0;

────────────────────────────────────────
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:652.981毫秒