我翻译的一篇文章,里面的内容并不完全同意。

原文在"十招编写更易维护的嵌入式代码"

为什么地址线要20条?

2008年9月09日 22:39

*缘起

在学习内存寻址的时候,大多数资料都写到:由于要满足80861M寻址空间,Intel的聪明的工程师想出了“段式”方法,来把1M空间分成64K段地址空间来管理,也就出现了所谓的段地址+段内偏移量来达到寻址的目的。这样的原因看起来很理所应当,而且的确非常漂亮。但是到了32位机器时代的来临,甚至64位的出现,这个架构始终面临着向后兼容的痛苦,要“兼容”这个段式寻址。

但我要提出的疑问是: 为什么当时会出现80861M的寻址空间呢?64K的地址空间就那么不够用么?非“逼着”大家想出来“段式”这么一个“可怕的”历史结果。不知道大家对于后面引起的实模式和保护模式

在经过“谷歌”以后,找到一个可以勉强解释的理由:

原文地址:http://blog.chinaunix.net/u/21948/showart_239664.html

“但当上升到16位机后,Intel8086/8088CPU的设计由于当年IC集成技术和外封装及引脚技术的限制,不能超过40个引脚。但又感觉到8位机原来的地址寻址能力2^1664KB太少了,但直接增加到16的整数倍即令AB32位又是达不到的。故而只能把AB暂时增加4条成为20条。则 2^201MB的寻址能力已经增加了16倍。但此举却造成了AB20位和DB16位之间的矛盾,20位地址信息既无法在DB上传送,又无法在16位的CPU寄存器和内存单元中存放。于是应运而生就产生了CPU段结构的原理。”

这里有个理由看来是是合理的:40个引脚的限制。先看一下8086长什么样子吧。

找到8086datasheet,查找其引脚定义:

可以看到,AD0AD15是分时复用的16条总线。这样就造成了期望在此基础上能够尽可能大的寻址,那么其中一条可选的也是很好的选择就是采用16位段寄存器+16位段内位移实现最大的且相对简单的寻址方式。

这就解决了我心中的那个疑惑。:)

memcpy还是memmove?

2008年7月18日 05:09

二话不说,先举例子:

例子1:

 

#include <stdio.h>
#include <STRING.H>

int main(void)
{
    char a[10] = "Hello!" ;
   
    printf("%s\r\n",a);

    memcpy(&a[2], a, 5);

    printf("%s\r\n",a);
   
    return 0;
}

 

例子2:

 

#include <stdio.h>
#include <STRING.H>

int main(void)
{
    char a[10] = "Hello!" ;
   
    printf("%s\r\n",a);

    memmove(&a[2], a, 5);
    printf("%s\r\n",a);
   
    return 0;
}

 

使用gcc 编译

$ gcc -v
Using built-in specs.
Target: i686-pc-cygwin
Configured with: ./configure
Thread model: single
gcc version 4.3.0 (GCC)
 

例子1的结果是:

 

$ ./a.exe
Hello!
HeHeHeH

例子2的结果是:

 

$ ./a.exe
Hello!
HeHello


从这两个简单的例子:我们可以看出memcpy和memmove的基本区别就是:源地址和目的地址是否可以重叠。(其实这个主要和库函数的实现有关)

为了明白这个问题:

我们看看memcpy的源码:

 

 

/* Copy memory to memory until the specified number of bytes
   has been copied.  Overlap is NOT handled correctly.
   Copyright (C) 1991, 1997 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Contributed by Torbjorn Granlund (tege@sics.se).

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */


#include <string.h>
#include <memcopy.h>
#include <pagecopy.h>

#undef memcpy

void *
memcpy (dstpp, srcpp, len)
     void *dstpp;
     const void *srcpp;
     size_t len;
{
  unsigned long int dstp = (long int) dstpp;
  unsigned long int srcp = (long int) srcpp;

  /* Copy from the beginning to the end.  */

  /* If there not too few bytes to copy, use word copy.  */
  if (len >= OP_T_THRES)
    {
      /* Copy just a few bytes to make DSTP aligned.  */
      len -= (-dstp) % OPSIZ;
      BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);

      /* Copy whole pages from SRCP to DSTP by virtual address manipulation,
         as much as possible.  */


      PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);

      /* Copy from SRCP to DSTP taking advantage of the known alignment of
         DSTP.  Number of bytes remaining is put in the third argument,
         i.e. in LEN.  This number may vary from machine to machine.  */


      WORD_COPY_FWD (dstp, srcp, len, len);

      /* Fall out and copy the tail.  */
    }

  /* There are just a few bytes to copy.  Use byte memory operations.  */
  BYTE_COPY_FWD (dstp, srcp, len);

  return dstpp;
}
 

 

 

我们来看看memmove的源码:

 

 

/* Copy memory to memory until the specified number of bytes
   has been copied.  Overlap is handled correctly.
   Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Contributed by Torbjorn Granlund (tege@sics.se).

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */


#include <string.h>
#include <memcopy.h>
#include <pagecopy.h>

/* All this is so that bcopy.c can #include
   this file after defining some things.  */

#ifndef a1
#define a1       dest   /* First arg is DEST.  */
#define a1const
#define a2       src    /* Second arg is SRC.  */
#define a2const  const
#undef memmove
#endif
#if     !defined(RETURN) || !defined(rettype)
#define RETURN(s)        return (s)      /* Return DEST.  */
#define rettype    void *
#endif


rettype
memmove (a1, a2, len)
     a1const void *a1;
     a2const void *a2;
     size_t len;
{
  unsigned long int dstp = (long int) dest;
  unsigned long int srcp = (long int) src;

  /* This test makes the forward copying code be used whenever possible.
     Reduces the working set.  */

  if (dstp - srcp >= len)       /* *Unsigned* compare!  */
    {
      /* Copy from the beginning to the end.  */

      /* If there not too few bytes to copy, use word copy.  */
      if (len >= OP_T_THRES)
        {
          /* Copy just a few bytes to make DSTP aligned.  */
          len -= (-dstp) % OPSIZ;
          BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);

          /* Copy whole pages from SRCP to DSTP by virtual address
             manipulation, as much as possible.  */


          PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);

          /* Copy from SRCP to DSTP taking advantage of the known
             alignment of DSTP.  Number of bytes remaining is put
             in the third argument, i.e. in LEN.  This number may
             vary from machine to machine.  */


          WORD_COPY_FWD (dstp, srcp, len, len);

          /* Fall out and copy the tail.  */
        }

      /* There are just a few bytes to copy.  Use byte memory operations.  */
      BYTE_COPY_FWD (dstp, srcp, len);
    }
  else
    {
      /* Copy from the end to the beginning.  */
      srcp += len;
      dstp += len;

      /* If there not too few bytes to copy, use word copy.  */
      if (len >= OP_T_THRES)
        {
          /* Copy just a few bytes to make DSTP aligned.  */
          len -= dstp % OPSIZ;
          BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);

          /* Copy from SRCP to DSTP taking advantage of the known
             alignment of DSTP.  Number of bytes remaining is put
             in the third argument, i.e. in LEN.  This number may
             vary from machine to machine.  */


          WORD_COPY_BWD (dstp, srcp, len, len);

          /* Fall out and copy the tail.  */
        }

      /* There are just a few bytes to copy.  Use byte memory operations.  */
      BYTE_COPY_BWD (dstp, srcp, len);
    }

  RETURN (dest);
}
 

一进函数我们“惊喜”的发现了:

 

if (dstp - srcp >= len)

这个对源地址目的地址进行了判断,如果地址没有重叠的话,我们可以看到memcpy和memmove所做的处理几乎完全相同;但在else里面我们看到了我们想要的内容。

基本处理思路:不是从前向后拷贝有可能会把还没有处理的数据会“冲掉”么?那么我们就从最后一个字符开始向前拷贝,这样就不会存在没有数据重叠了吧。。:)

前面提到这个问题和库函数的实现有关: 如果拿VC6.0作为编译器的话,其库的实现memcpy和memmove的结果是一样的。这样处理的原因不明。哪位知道讲解一下或者有代码让我看看都不胜感激!