+ -
当前位置:首页 → 问答吧 → memset的指针用long int是因为那个时候C99还没出来吗?

memset的指针用long int是因为那个时候C99还没出来吗?

时间:2010-08-02

来源:互联网

memset的指针用long int是因为那个时候C99还没出来吗? 不然为什么不用void *.
还是说这么可以提高效率?

作者: yylogo   发布时间: 2010-08-02

是说内部实现么?

作者: hellioncu   发布时间: 2010-08-02

回复 yylogo

啥? void*?

你是说函数原型是long int? 还是说copy的时候用long int?

作者: OwnWaterloo   发布时间: 2010-08-02

还真看到函数原型是void *的,不知道楼主说的是不是这个

作者: daybreakcx   发布时间: 2010-08-02

本帖最后由 yylogo 于 2010-08-02 17:24 编辑

下面是代码,里面的注释是我写的,我把原来的注释删了,到时候发表到博客里面去。
http://zqynux.blog.163.com/
  1. void *memset(void *dstpp, int c, size_t len)
  2. {
  3.         long int dstp = (long int) dstpp;
  4.         /* 正在翻阅为什么用long int 而不是void * */

  5.         if (len >= 8) {
  6.                 size_t xlen;
  7.                 op_t cccc;
  8.                 /* 关于op_t这个类型, 在memcmp中有定义
  9.                         # define op_t        unsigned long int
  10.                         # define OPSIZ        (sizeof(op_t)) */


  11.                 /* 每次操作对多个字节进行赋值 */
  12.                 cccc = (unsigned char) c;
  13.                 cccc |= cccc << 8;
  14.                 cccc |= cccc << 16;
  15.                 if (OPSIZ > 4)                /* 如果是64位的机子的话, 还可以再多用4个字节 */
  16.                         cccc |= (cccc << 16) << 16;

  17.                 while (dstp % OPSIZ != 0) {        /* 让内存地址对齐地址总线的长度, 以
  18.                                                                      得到最高的效率! */
  19.                         ((byte *) dstp)[0] = c;
  20.                         dstp += 1;
  21.                         len -= 1;
  22.                 }

  23.                 xlen = len / (OPSIZ * 8);        /* 每次赋值8个,也就是说如果在32位的机子上的话
  24.                                                 每次赋值4*8=32个字节,64位的机子就是64字节 */
  25.                 while (xlen > 0) {
  26.                         ((op_t *) dstp)[0] = cccc;
  27.                         ((op_t *) dstp)[1] = cccc;
  28.                         ((op_t *) dstp)[2] = cccc;
  29.                         ((op_t *) dstp)[3] = cccc;
  30.                         ((op_t *) dstp)[4] = cccc;
  31.                         ((op_t *) dstp)[5] = cccc;
  32.                         ((op_t *) dstp)[6] = cccc;
  33.                         ((op_t *) dstp)[7] = cccc;
  34.                         dstp += 8 * OPSIZ;
  35.                         xlen -= 1;
  36.                 }
  37.                 len %= OPSIZ * 8;                /* 得到余下的未赋值的字节数,一定小于32 */

  38.                 xlen = len / OPSIZ;                /* 每次赋值1个, 32位机子4个字节一次, 64位8个 */
  39.                 while (xlen > 0) {
  40.                         ((op_t *) dstp)[0] = cccc;
  41.                         dstp += OPSIZ;
  42.                         xlen -= 1;
  43.                 }
  44.                 len %= OPSIZ;                        /* 得到余下的未赋值的字节书,一定小于4 */
  45.         }

  46.         while (len > 0) {                        /* 最后剩下的几个字节单独赋值 */
  47.                 ((byte *) dstp)[0] = c;
  48.                 dstp += 1;
  49.                 len -= 1;
  50.         }

  51.         return dstpp;
  52. }
复制代码

作者: yylogo   发布时间: 2010-08-02

就是dstp这个变量,(哇,这个内容回复好快!!)

作者: yylogo   发布时间: 2010-08-02

回复 yylogo

一次性复制一个机器字相比将机器字拆分成若干个byte来说, 确实效率会高。

作者: OwnWaterloo   发布时间: 2010-08-02

回复 OwnWaterloo


    我是问那个变量为什么不用void *还是long int,是不是其中还有什么奥妙。

作者: yylogo   发布时间: 2010-08-02

回复 yylogo

void*不能增。

我奇怪的是为什么不用char*。

作者: OwnWaterloo   发布时间: 2010-08-02

回复 OwnWaterloo


    哦,, 我错了...
    高手就是高手..

作者: yylogo   发布时间: 2010-08-02

谁说一定要用 long int 了?具体采用什么,那是实现者的事。

http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/string/memset.c?rev=1.9

作者: langue   发布时间: 2010-08-02

本帖最后由 yylogo 于 2010-08-02 17:34 编辑

回复 langue


    哦, 就是这么一回事啊.. 我以为有什么玄机呢.
    不过FreeBSD的这个好难理解..

作者: yylogo   发布时间: 2010-08-02

回复 yylogo

你blog中那个泡泡兵的表情笑死我了……
推荐放弃网易blog, 改用is-programmer或者cppblog……

作者: OwnWaterloo   发布时间: 2010-08-02

本帖最后由 yylogo 于 2010-08-02 17:36 编辑

回复 OwnWaterloo


    额,, 那个is-programmer, cppblog可以搬家吧?
    一篇一篇复制太麻烦了, 而且网易里面还有一些OIer, 不知道is-programmer里面有没有

作者: yylogo   发布时间: 2010-08-02

is-programmer里头的TeX数学公式插件很过瘾的说

作者: daybreakcx   发布时间: 2010-08-02

回复 langue


    额,,, 有点近似无语了,,  FreeBSD 这一个东西实现俩函数?
    我再琢磨下

作者: yylogo   发布时间: 2010-08-02

回复 yylogo

仔细一看……   文章挺多……
而且, 你才15岁啊?  前途无量……

搬家么, 不一定需要搬吧? 转过去就是了。
网易不是专为程序员打造的blog, 我记得连回复订阅的功能都没有。

cppblog人气高。 你在首页上发一贴, 一天的流量就比你现在的多了。
is-programmer的功能很齐全, 但好像没cppblog人这么多。

作者: OwnWaterloo   发布时间: 2010-08-02

回复 daybreakcx

对对。

搞oi, 总要写点公式吧?  公式复杂了总要用tex吧?
is-programmer就是我搜tex online时搜到的……

作者: OwnWaterloo   发布时间: 2010-08-02

回复 OwnWaterloo


    恩, 这个我再琢磨下..

作者: yylogo   发布时间: 2010-08-02

回复 langue


    问问(length & wmask) 是什么意思? wmask在32位的机子就是3吧?
    那如果length 在后两位都是零怎么办?

作者: yylogo   发布时间: 2010-08-02

回复 langue


    哦,, 我知道了, 这也是地址对齐的功能

作者: yylogo   发布时间: 2010-08-02

回复 OwnWaterloo


    额, 前途无量啊. .. OI比我厉害的人多的是, 我又想搞下Linux.. 三心二意的, 我还不知道怎么办...

作者: yylogo   发布时间: 2010-08-02

回复 yylogo

是的,题外话是这件事可以追溯到较早以前,大概 17 年前,也就是在 4.4BSD 发布的时候,bzero.c 的内容合并到了 memset.c,这一个文件就同时实现了 bzero(3) 和 memset(3)。

作者: langue   发布时间: 2010-08-02

回复 yylogo

OI没要求OS吧?  先抓OI, linux等拿到奖后再慢慢玩。
好像现在不加分了?

作者: OwnWaterloo   发布时间: 2010-08-02

回复 langue


    那我冒昧的问句, 这不同时只能实现一个函数?

作者: yylogo   发布时间: 2010-08-02

回复 OwnWaterloo


    Yes, you are right!!!

作者: yylogo   发布时间: 2010-08-02

gcc -c memset.c
gcc -c -DBZERO memset.c -o bzero.o
gcc memset.o bzero.o
...
  1. void* memset(void* dst, int val, size_t len) { ... }
  2. void bzero(void* dst, size_t len) { memset(dst, 0, len); }
复制代码
如果编译器不能将上面的代码优化到bsd那样, 可以丢了。
如果可以优化到一样, 那bsd的写法就碍眼了。

作者: OwnWaterloo   发布时间: 2010-08-02

回复 yylogo

确实不太公平……  其他竞赛都可以加, 凭什么OI不行……

作者: OwnWaterloo   发布时间: 2010-08-02

回复 OwnWaterloo


    哦, 编译两次, 第一次加宏bezro, 第二次不要..

作者: yylogo   发布时间: 2010-08-02

回复 yylogo

确实同时只实现一个,在编译时根据参数的不同来做一定的调整。参考 src/lib/string/Makefile.inc

bzero.o: memset.c
        ${CC} -DBZERO ${CFLAGS} -c ${.ALLSRC} -o ${.TARGET}
        @${LD} -x -r ${.TARGET}
        @mv a.out ${.TARGET}

作者: langue   发布时间: 2010-08-02

热门下载

更多