zoukankan      html  css  js  c++  java
  • C的memset,memcpy,strcpy 的区别 及memset memcpy memmove源码

    extern void *memcpy(void *dest,void *src,unsigned int count);
    #include <string.h>
       功能:由src所指内存区域复制count个字符串到dest所指内存区域.
       说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针.
       
       memset
       extern void *memset(void *buffer,int c,int count);
       #include <string.h>
       功能:把buffer所指内存区域的前count个字节设置成字符c
       说明:返回指向buffer的指针.

    二.区别
        memset 用来对一段内存空间全部设置为某个字符,一般用于在对定义的字符串初始化为' '或者'';
        例: char a[100];
              memset(a,'',sizeof(a));
        
       memcpy 是用来做内存拷贝,可以用来拷贝任何数据类型的对象,可以指定拷贝的数据长度;
       例:
               char a[100],b[50];
               memcpy(b,a,sizeof(b));   //注意:如果使用sizeof(a),会造成内存溢出
       mem是一段内存,他的长度,必须自己记住.memcpy是见着什么拷贝什么。
        
        strcpy 就只能拷贝字符串,它遇到''就结束拷贝;
          例:char a[100],b[50];
                  strcpy(a,b);
                  如用strcpy(b,a)要注意a中的字符串长度(第一个''之前) 是否超过50,如果超过,则会造成b的
    内存溢出.它是不会拷贝''的,所以一般还有加一个语句:
                  *a='';
       
    三.使用技巧
          memset 可以方便的清空一个数据结构的变量或数组.
          如:
            struct sample_struct
           {
                  char csName[16];
                  int iSeq;
                  int iType;
           };
           对于变量
           struct sample_struct stTest;
           一般情况下,初始化stTest的方法:
            stTest.csName[0]='';
            stTest.iSeq=0;
            stTest.iType=0;
        而用memset:
           memset(&stTest,0,sizeof(struct sample_struct));
        如果是数组:
        struct sample_struct TEST[100];
        memset(TEST,0,sizeof(struct sample_struct)*100);

    strcpy是拷贝字符串,以为标志结束(即一旦遇到数据值为0的内存地址拷贝过程即停止) 
    strcpy的原型为 
    char *strcpy(char *dest, const char *src) 
    memcpy是给定来源和目标后,拷贝指定大小n的内存数据,而不管拷贝的内容是什么(不仅限于字符) 
    memcpy的原型为 
    void *memcpy(void *dest, const void *src, size_t n);

    memcpy源码:

    /***
    *memcpy.c - contains memcpy routine
     
    *Purpose:
    *       memcpy() copies a source memory buffer to a destination buffer.
    *       Overlapping buffers are not treated specially, so propogation may occur.
    *
     **********/
    
    #include <cruntime.h>
    #include <string.h>
    
    #pragma function(memcpy)
    
    /***
    *memcpy - Copy source buffer to destination buffer
    *
    *Purpose:
    *       memcpy() copies a source memory buffer to a destination memory buffer.
    *       This routine does NOT recognize overlapping buffers, and thus can lead
    *       to propogation.
    *
    *       For cases where propogation must be avoided, memmove() must be used.
    *
    *Entry:
    *       void *dst = pointer to destination buffer
    *       const void *src = pointer to source buffer
    *       size_t count = number of bytes to copy
    *
    *Exit:
    *       Returns a pointer to the destination buffer
    *
    *Exceptions:
    *******************************************************************************/
    
    void * __cdecl memcpy (
            void * dst,
            const void * src,
            size_t count
            )
    {
            void * ret = dst;
    
    #if defined (_M_IA64)
    
            {
    
    
            __declspec(dllimport)
    
    
            void RtlCopyMemory( void *, const void *, size_t count );
    
            RtlCopyMemory( dst, src, count );
    
            }
    
    #else  /* defined (_M_IA64) */
            /*
             * copy from lower addresses to higher addresses
             */
            while (count--) {
                    *(char *)dst = *(char *)src;
                    dst = (char *)dst + 1;
                    src = (char *)src + 1;
            }
    #endif  /* defined (_M_IA64) */
    
            return(ret);
    }

    实现很简单,count一直减,把src值赋给dest,唯一值得注意的是函数原型。

    void * __cdecl memcpy (
            void * dst,
            const void * src,
            size_t count
            )

    可以看到参数为void 类型的指针
    ,也返回一个void *指针。
    我们可以利用void *类型指针为任何类型实现copy,如结构体:
        struct A{
            int x;
            int y;
        };
        A *a=new A();
        A *b=new A();
        a->x=5;
        a->y=3;
         
        memcpy(b,a,sizeof(A));
        printf("%d%d
    ",b->x,b->y);

    输出53。

    memset源码:

    /***
    *char *memset(dst, val, count) - sets "count" bytes at "dst" to "val"
    *
    *Purpose:
    *       Sets the first "count" bytes of the memory starting
    *       at "dst" to the character value "val".
    *
    *Entry:
    *       void *dst - pointer to memory to fill with val
    *       int val   - value to put in dst bytes
    *       size_t count - number of bytes of dst to fill
    *
    *Exit:
    *       returns dst, with filled bytes
    *
    *Exceptions:
    *
    *******************************************************************************/
    
    void * __cdecl memset (
            void *dst,
            int val,
            size_t count
            )
    {
            void *start = dst;
    
    #if defined (_M_IA64) || defined (_M_AMD64)
    
            {
    
    
            __declspec(dllimport)
    
    
            void RtlFillMemory( void *, size_t count, char );
    
            RtlFillMemory( dst, count, (char)val );
    
            }
    
    #else  /* defined (_M_IA64) || defined (_M_AMD64) */
            while (count--) {
                    *(char *)dst = (char)val;
                    dst = (char *)dst + 1;
            }
    #endif  /* defined (_M_IA64) || defined (_M_AMD64) */
    
            return(start);
    }

    1.memmove

    函数原型:void *memmove(void *dest, const void *source, size_t count)

    返回值说明:返回指向dest的void *指针

    参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数

    函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。

    2.memcpy

    函数原型:void *memcpy(void *dest, const void *source, size_t count);

    返回值说明:返回指向dest的void *指针

    函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。

    3.两者区别

      函数memcpy()   从source  指向的区域向dest指向的区域复制count个字符,如果两数组重叠,不定义该函数的行为。   
      而memmove(),如果两函数重叠,赋值仍正确进行。

      memcpy函数假设要复制的内存区域不存在重叠,如果你能确保你进行复制操作的的内存区域没有任何重叠,可以直接用memcpy;   
      如果你不能保证是否有重叠,为了确保复制的正确性,你必须用memmove。

     memcpy的效率会比memmove高一些,如果还不明白的话可以看一些两者的实现:

    复制代码

    void *memmove(void *dest, const void *source, size_t count)
    {
     assert((NULL != dest) && (NULL != source));
     char *tmp_source, *tmp_dest;
     tmp_source = (char *)source;
     tmp_dest = (char *)dest;
     if((dest + count<source) || (source + count) <dest))
     {// 如果没有重叠区域
       while(count--)
         *tmp_dest++ = *tmp_source++;
    }
    else
    { //如果有重叠
     tmp_source += count - 1;
     tmp_dest += count - 1;
     while(count--)
       *--tmp_dest = *--tmp;
    }
    return dest;
    }
    复制代码


    void *memcpy(void *dest, const void *source, size_t count)
    {
     assert((NULL != dest) && (NULL != source));
     char *tmp_dest = (char *)dest;
     char *tmp_source = (char *)source;
     while(count --)//不对是否存在重叠区域进行判断
       *tmp_dest ++ = *tmp_source ++;
     return dest;
    }

    memmove普通实现

    memmove - Copy source buffer to destination buffer
    ;
    ;Purpose:
    ;       memmove() copies a source memory buffer to a destination memory buffer.
    ;       This routine recognize overlapping buffers to avoid propogation.
    ;       For cases where propogation is not a problem, memcpy() can be used.
    ;
    ;   Algorithm:

        void* memmove(void* dest, void* source, size_t count)

       {

           void* ret = dest;

     

           if (dest <= source || dest >= (source + count))

           {

              //Non-Overlapping Buffers
             //copy from lower addresses to higher addresses
        

             while (count --)

                   *dest++ = *source++;

         }

         else

         {

            //Overlapping Buffers
           //copy from higher addresses to lower addresses

     

           dest += count - 1;

           source += count - 1;

           while (count--)

                    *dest-- = *source--;l

          }

          return ret;

       }

     

    另一种实现:

    void* mymemcpy( void* dest, const void* src, size_t count )
    {
        char* d = (char*)dest;
        const char* s = (const char*)src;
      //  int n = (count + 7) / 8; // count > 0 assumed
        int n = count >> 3;
        switch( count & 7 )
        {
                  do {  *d++ = *s++;
        case 7:        *d++ = *s++;
        case 6:        *d++ = *s++;
        case 5:        *d++ = *s++;
        case 4:        *d++ = *s++;
        case 3:        *d++ = *s++;
        case 2:        *d++ = *s++;
        case 1:        *d++ = *s++;
        case 0          } //while (--n > 0);
                     while (n-- > 0)
        }

        return dest;
    }



  • 相关阅读:
    转:浅谈Linux的内存管理机制
    (转)Redis
    检测socket链接是否断开
    linux C 中的volatile使用
    LINUX 下 ipv6 socket 编程
    linux signal 列表
    Linux下异常信号
    linux signal
    转: 关于Linux常用的二进制文件分析方法
    IOI2020 题解
  • 原文地址:https://www.cnblogs.com/youxin/p/3271074.html
Copyright © 2011-2022 走看看